diff --git a/lib/channel.rb b/lib/channel.rb new file mode 100644 index 00000000..1f6d4e51 --- /dev/null +++ b/lib/channel.rb @@ -0,0 +1,32 @@ +module SlackBot + class Channel < Recipient + PATH_URL = "channels.list?" + attr_reader :num_members, :name, :id + + def initialize(num_members:, name:, id:) + @num_members = num_members + @name = name + @id = id + end + + def self.list + response = get(PATH_URL) + check_response_code(response) + + channels_array = response["channels"].map do |channel| + SlackBot::Channel.new(num_members: channel["num_members"], name: channel["name"], id: channel["id"]) + end + + return channels_array + end + + def details + channel_details = { + num_members: @num_members, + name: @name, + id: @id, + } + return channel_details + end + end +end diff --git a/lib/recipient.rb b/lib/recipient.rb new file mode 100644 index 00000000..bed56070 --- /dev/null +++ b/lib/recipient.rb @@ -0,0 +1,43 @@ +module SlackBot + class SlackApiError < StandardError; end + + class Recipient + BASE_URL = "https://slack.com/api/" + TOKEN = ENV["TOKEN"] + def self.list + raise NotImplementedError + end + + def details + raise NotImplementedError + end + + def send_message(message) + body = { + text: message, + channel: id, + token: TOKEN, + } + response = HTTParty.post("#{BASE_URL}chat.postMessage", body: body, headers: { "Content-type" => "application/x-www-form-urlencoded" }) + unless response.code == 200 && response.parsed_response["ok"] + raise SlackApiError, "Error when posting #{message} to #{id}, error: #{response.parsed_response["error"]}" + end + + return true + end + + def self.check_response_code(response) + unless response.code == 200 && response.parsed_response["ok"] + raise SlackApiError, "Error when posting #{message} to #{id}, error: #{response.parsed_response["error"]}" + end + end + + private + + def self.get(path_url) + query_parameters = { token: TOKEN } + response = HTTParty.get("#{BASE_URL}#{path_url}", query: query_parameters) + return response + end + end +end diff --git a/lib/slack.rb b/lib/slack.rb index 960cf2f7..69aec403 100755 --- a/lib/slack.rb +++ b/lib/slack.rb @@ -1,11 +1,91 @@ #!/usr/bin/env ruby +require "table_print" +require "HTTParty" +require "dotenv" +Dotenv.load + +require_relative "../lib/recipient.rb" +require_relative "../lib/user.rb" +require_relative "../lib/channel.rb" +require_relative "../lib/workspace.rb" + +def get_user_options_input(options) + input = gets.chomp.to_s.strip + until options.include?(input) + puts "Please choose option from list" + input = gets.chomp.to_s.strip + end + puts "\n" + return input +end + +def get_user_input(message_to_user) + input = gets.chomp.to_s.strip + until input.length > 0 + puts message_to_user + input = gets.chomp.to_s.strip + end + puts "\n" + return input +end + +def list_options + puts "\nPlease choose from these options:\n\n" + puts "Enter 'list users' to view all users" + puts "Enter 'list channels' to view all channels" + puts "Enter 'select user' to select a user" + puts "Enter 'select channel' to select a channel" + puts "Enter 'details' to display information about currently selected recipient" + puts "Enter 'send message' to send a message to selected recipient" + puts "Enter 'quit' to quit\n\n" +end def main puts "Welcome to the Ada Slack CLI!" + workspace = SlackBot::Workspace.new - # TODO project + while true + list_options + options = ["list users", "list channels", "select user", "select channel", "details", "send message", "quit"] + choice = get_user_options_input(options) + case choice + when "list users" + tp workspace.list_users + when "list channels" + tp workspace.list_channels + when "select user" + puts "Please enter a user ID or user name:" + input = get_user_input("Please enter an ID or name") + selected = workspace.select_user(input) + puts "Sorry, no user with that information" if selected == nil + when "select channel" + puts "Please enter a channel name channel ID" + input = get_user_input("Please enter an ID or name") + selected = workspace.select_channel(input) + puts "Sorry, no channel with that information" if selected == nil + when "details" + if workspace.selected + tp [selected.details] + else + puts "Please select a user or channel first" + end + when "send message" + if !workspace.selected + puts "A recipient needs to be selected first" + else + puts "Enter the message you would like to send: " + message_to_send = get_user_input("Message must be at least one character") + workspace.send_message(message_to_send) + puts "Message sent!" + end + when "quit" + puts "Goodbye!" + exit + end + puts "\n\n" + end puts "Thank you for using the Ada Slack CLI" end -main if __FILE__ == $PROGRAM_NAME \ No newline at end of file +main if __FILE__ == $PROGRAM_NAME diff --git a/lib/slack_api_error.rb b/lib/slack_api_error.rb new file mode 100644 index 00000000..e69de29b diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 00000000..9266bd6c --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,34 @@ +require "pry" + +module SlackBot + class User < Recipient + PATH_URL = "users.list?" + attr_reader :real_name, :name, :id + + def initialize(real_name:, name:, id:) + @real_name = real_name + @name = name + @id = id + end + + def self.list + response = get(PATH_URL) + check_response_code(response) + + users_array = response["members"].map do |user| + SlackBot::User.new(real_name: user["real_name"], name: user["name"], id: user["id"]) + end + + return users_array + end + + def details + user_details = { + real_name: @real_name, + name: @name, + id: @id, + } + return user_details + end + end +end diff --git a/lib/workspace.rb b/lib/workspace.rb new file mode 100644 index 00000000..06a8430c --- /dev/null +++ b/lib/workspace.rb @@ -0,0 +1,45 @@ +module SlackBot + class Workspace + attr_reader :users, :channels, :selected + + def initialize + @users = SlackBot::User.list + @channels = SlackBot::Channel.list + @selected = nil + end + + def list_users + user_list = @users.map do |user| + user.details + end + return user_list + end + + def list_channels + channel_list = @channels.map do |channel| + channel.details + end + return channel_list + end + + def select_user(input) + found_user = @users.find do |user| + input == user.id || input == user.name + end + @selected = found_user + end + + def select_channel(input) + found_channel = @channels.find do |channel| + input == channel.id || input == channel.name + end + @selected = found_channel + end + + def send_message(message) + return false if !selected + selected.send_message(message) + return true + end + end +end diff --git a/specs/channel_spec.rb b/specs/channel_spec.rb new file mode 100644 index 00000000..9646abea --- /dev/null +++ b/specs/channel_spec.rb @@ -0,0 +1,47 @@ +require_relative "test_helper" + +describe "channel" do + describe "self.list" do + it "Returns an array of hashes" do + VCR.use_cassette("self.list") do + channel_list = SlackBot::Channel.list + + expect(channel_list).must_be_kind_of Array + expect(channel_list.first).must_be_kind_of SlackBot::Channel + expect(channel_list.last).must_be_kind_of SlackBot::Channel + end + end + it "Returns a real_name" do + VCR.use_cassette("self.list") do + channel_list = SlackBot::Channel.list + + expect(channel_list.first.num_members).must_equal 2 + expect(channel_list.first.id).must_equal "CH2P99HT5" + expect(channel_list.first.name).must_equal "slack-api-project" + end + end + end + describe "send message" do + before do + VCR.use_cassette("send message to channel") do + @channel_list = SlackBot::Channel.list + end + end + + it "returns true if given a valid message" do + VCR.use_cassette("send message with empty string to channel") do + message = "Hello!" + expect(@channel_list.first.send_message(message)).must_equal true + end + end + + it "returns a slackapierror when given an empty string" do + VCR.use_cassette("send message with empty string to channel") do + message = "" + expect { + @channel_list.first.send_message(message) + }.must_raise SlackBot::SlackApiError + end + end + end +end diff --git a/specs/recipient_spec.rb b/specs/recipient_spec.rb new file mode 100644 index 00000000..f917f426 --- /dev/null +++ b/specs/recipient_spec.rb @@ -0,0 +1,20 @@ +require_relative "test_helper" + +describe "Recipient" do + describe "self.list" do + it "Raises NotImplementedError if called directly on recipient" do + expect { + SlackBot::Recipient.list + }.must_raise NotImplementedError + end + end + + describe "details" do + it "Raise NotImplementedError if called directory on recipient" do + recipient = SlackBot::Recipient.new + expect { + recipient.details + }.must_raise NotImplementedError + end + end +end diff --git a/specs/test_helper.rb b/specs/test_helper.rb index 81ccd06b..24762ca6 100644 --- a/specs/test_helper.rb +++ b/specs/test_helper.rb @@ -1,15 +1,33 @@ -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 "HTTParty" +require "vcr" +require "webmock/minitest" +require "dotenv" +require "pry" +Dotenv.load 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.default_cassette_options = { + :record => :new_episodes, + :match_requests_on => [:method, :uri, :body], + } + + config.filter_sensitive_data("") do + ENV["TOKEN"] + end +end + +require_relative "../lib/recipient.rb" +require_relative "../lib/user.rb" +require_relative "../lib/channel.rb" +require_relative "../lib/workspace.rb" diff --git a/specs/user_spec.rb b/specs/user_spec.rb new file mode 100644 index 00000000..a06aa668 --- /dev/null +++ b/specs/user_spec.rb @@ -0,0 +1,59 @@ +require_relative "test_helper" +require "pry" + +describe "user" do + describe "initialize" do + before do + @new_user = SlackBot::User.new(real_name: "Sarah", name: "Riyo", id: "USRJFDJFKD") + end + + it "creates an instance of user" do + expect(@new_user).must_be_kind_of SlackBot::User + end + end + describe "self.list" do + it "Returns an array of hashes" do + VCR.use_cassette("self.list") do + user_list = SlackBot::User.list + + expect(user_list).must_be_kind_of Array + expect(user_list.first).must_be_kind_of SlackBot::User + expect(user_list.last).must_be_kind_of SlackBot::User + end + end + it "Returns users real_name, id and name" do + VCR.use_cassette("self.list") do + user_list = SlackBot::User.list + + expect(user_list.first.real_name).must_equal "Slackbot" + expect(user_list.first.id).must_equal "USLACKBOT" + expect(user_list.first.name).must_equal "slackbot" + end + end + + end + describe "send message" do + before do + VCR.use_cassette("send message") do + @user_list = SlackBot::User.list + end + end + + + it "returns true if given a valid message" do + VCR.use_cassette("send working message") do + message = "Hello!" + expect(@user_list.first.send_message(message)).must_equal true + end + end + + it "returns a slackapierror when given an empty string" do + VCR.use_cassette("send message with empty string") do + message = "" + expect { + @user_list.first.send_message(message) + }.must_raise SlackBot::SlackApiError + end + end + end +end diff --git a/specs/workspace_spec.rb b/specs/workspace_spec.rb new file mode 100644 index 00000000..746e4337 --- /dev/null +++ b/specs/workspace_spec.rb @@ -0,0 +1,120 @@ +require_relative "test_helper" + +describe "Workspace" do + describe "Initialize" do + before do + VCR.use_cassette("initialize") do + @workspace = SlackBot::Workspace.new + end + end + it "Creates a workspace object" do + expect(@workspace).must_be_kind_of SlackBot::Workspace + end + + it "Initializes with selected equal to nil" do + assert_nil @workspace.selected + end + it "Creates a list of users" do + expect(@workspace.users).must_be_kind_of Array + expect(@workspace.users.first).must_be_kind_of SlackBot::User + expect(@workspace.users.first.real_name).must_equal "Slackbot" + expect(@workspace.users.first.name).must_equal "slackbot" + expect(@workspace.users.first.id).must_equal "USLACKBOT" + end + end + describe "list" do + before do + VCR.use_cassette("list") do + @workspace = SlackBot::Workspace.new + end + end + it "returns an array of hashes for list_users" do + users = @workspace.list_users + expect(users).must_be_kind_of Array + expect(users.first).must_be_kind_of Hash + expect(users.first[:name]).must_equal "slackbot" + expect(users.first[:id]).must_equal "USLACKBOT" + expect(users.first[:real_name]).must_equal "Slackbot" + end + it "returns an array of hashes for list_channel" do + channels = @workspace.list_channels + expect(channels).must_be_kind_of Array + expect(channels.first).must_be_kind_of Hash + expect(channels.first[:name]).must_equal "slack-api-project" + expect(channels.first[:id]).must_equal "CH2P99HT5" + expect(channels.first[:num_members]).must_equal 2 + end + end + describe "select" do + before do + VCR.use_cassette("select") do + @workspace = SlackBot::Workspace.new + end + end + it "returns nil if no user found with id given" do + selected = @workspace.select_user("USLACKNOT") + assert_nil selected + end + it "returns nil if no user found with name given" do + selected = @workspace.select_user("Devin") + assert_nil selected + end + it "returns a User object if given a valid user id" do + selected = @workspace.select_user("USLACKBOT") + expect(selected).must_be_kind_of SlackBot::User + expect(selected.name).must_equal "slackbot" + end + it "returns a User object if given a valid user name" do + selected = @workspace.select_user("slackbot") + expect(selected).must_be_kind_of SlackBot::User + expect(selected.id).must_equal "USLACKBOT" + end + + it "returns nil if no channel found with id given" do + selected = @workspace.select_channel("CH2P99HT6") + assert_nil selected + end + it "returns nil if no channel found with name given" do + selected = @workspace.select_channel("slack-bpi-project") + assert_nil selected + end + it "returns a Channel object if given a valid user id" do + selected = @workspace.select_channel("CH2SL5C3C") + expect(selected).must_be_kind_of SlackBot::Channel + expect(selected.name).must_equal "everyone" + end + it "returns a Channel object if given a valid name" do + selected = @workspace.select_channel("random") + expect(selected).must_be_kind_of SlackBot::Channel + expect(selected.id).must_equal "CH2SL5DEW" + end + end + describe "send message" do + before do + VCR.use_cassette("select") do + @workspace = SlackBot::Workspace.new + end + end + + it "returns false if no user or channel is selected" do + expect(@workspace.send_message("Hi")).must_equal false + end + + it "returns a slackapierror when given an empty message" do + VCR.use_cassette("send message with empty string") do + message = "" + expect { + @workspace.users.first.send_message(message) + }.must_raise SlackBot::SlackApiError + end + end + + it "returns true if given a valid message and valid user/channel selected" do + VCR.use_cassette("send message with empty string") do + message = "Hello!" + @workspace.select_user(@workspace.users.first.id) + expect(@workspace.send_message(message)).must_equal true + end + end + end +end