diff --git a/.gitignore b/.gitignore index 3ff4fada..a8783b85 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ # Ignore environemnt variables .env +.floo +.flooignore +.idea/ diff --git a/lib/channel.rb b/lib/channel.rb new file mode 100644 index 00000000..2899f89b --- /dev/null +++ b/lib/channel.rb @@ -0,0 +1,27 @@ +require_relative 'recipient' + +CONVERSATIONS_LIST_URL = "https://slack.com/api/conversations.list" + +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.to_i + end + + def details + return "Channel id: #{@slack_id}\nChannel name: #{@name}\nTopic: #{@topic}\nNumber of members: #{@member_count}" + end + + def self.list_all + query = {token: ENV["SLACK_TOKEN"]} + + request = self.get(CONVERSATIONS_LIST_URL, query: query) + + return request["channels"].map do |channel| + self.new(channel["id"], channel["name"], channel["purpose"]["value"], channel["num_members"].to_i) + end + end +end diff --git a/lib/recipient.rb b/lib/recipient.rb new file mode 100644 index 00000000..1b386a34 --- /dev/null +++ b/lib/recipient.rb @@ -0,0 +1,39 @@ +require 'httparty' + +POST_URL = "https://slack.com/api/chat.postMessage" + +class Recipient + attr_reader :slack_id, :name + + def initialize(slack_id, name) + @slack_id = slack_id + @name = name + end + + def send_message(message) + params = {token: ENV['SLACK_TOKEN'], channel: @slack_id, text: message} + return self.class.error_message(HTTParty.post(POST_URL, body: params)) + end + + def self.get(url, params) + return error_message(HTTParty.get(url,params)) + end + + def details + raise NotImplementedError, 'Implement me in a child class!' + end + def self.list_all + raise NotImplementedError, 'Implement me in a child class!' + end + + private + + def self.error_message(response) + if response["ok"] != true + raise ArgumentError, "API request failed with error: #{response["error"]}." + else + return response + end + end + +end \ No newline at end of file diff --git a/lib/slack.rb b/lib/slack.rb index 8a0b659b..e1d81cc8 100755 --- a/lib/slack.rb +++ b/lib/slack.rb @@ -1,12 +1,98 @@ #!/usr/bin/env ruby +require 'dotenv' +require "table_print" +require_relative 'workspace' + def main + Dotenv.load + puts "Welcome to the Ada Slack CLI!" workspace = Workspace.new + workspace.load_users + workspace.load_channels + puts "Amount of users in workspace: #{workspace.users.length}" + puts "Amount of channels in workspace: #{workspace.channels.length}" + + + puts "1. list users\n2. list channels\n3. select user\n4. select channel\n5. quit" + selection = number_validation(gets.chomp, 5) - # TODO project + while (1..4).include? selection + case selection + when 1 + tp workspace.users, "slack_id", "name", "real_name", "status_text", "status_emoji" + when 2 + tp workspace.channels, "slack_id", "name", "topic", "member_count" + when 3, 4 + puts "Please input a name or slack id" + if selection == 3 + selected_recipient = workspace.select_user(gets.chomp) + else + selected_recipient = workspace.select_channel(gets.chomp) + end + + if selected_recipient + puts "Would you like details? (yes/no)" + details_selection = input_validation(gets.chomp.downcase) + if details_selection == "yes" + puts workspace.show_details(selected_recipient) + end + puts "Would you like to #{selected_recipient.class == User ? "send a message" : "post"} to #{selected_recipient.name}? (yes/no)" + message_selection = input_validation(gets.chomp.downcase) + if message_selection == "yes" + puts "Please write your message." + message = gets.chomp + selected_recipient.send_message(message) + end + else + puts "No #{(selection == 3) ? "user" : "channel"} found." + end + + end + + puts "Make another selection:" + puts "1. list users\n2. list channels\n3. select user\n4. select channel\n5. quit" + selection = number_validation(gets.chomp, 5) + end puts "Thank you for using the Ada Slack CLI" end +def number_validation(input, max_num) + input = translate_input(input) + + until (1..max_num).include? input + puts "Invalid input. Please re-enter a selection." + input = translate_input(gets.chomp) + end + + return input +end + +def input_validation(input) + until ["yes", "no"].include? input + puts "Invalid input. Please re-enter either a yes or no." + input = gets.chomp.downcase + end + return input +end + +def translate_input(string_input) + case string_input.downcase + when "list users", "1" + return 1 + when "list channels", "2" + return 2 + when "select user", "3" + return 3 + when "select channel", "4" + return 4 + when "quit", "5" + return 5 + else + return string_input + end +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..683c3763 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,28 @@ +require_relative 'recipient' + +USERS_LIST_URL = "https://slack.com/api/users.list" + +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 + + def details + return "User id: #{@slack_id}\nUsername: #{@name}\nReal name: #{@real_name}\nStatus text: #{@status_text}\nStatus emoji: #{@status_emoji}" + end + + def self.list_all + query = {token: ENV['SLACK_TOKEN']} + + request = self.get(USERS_LIST_URL, query: query) + + @users = request["members"].map do |user| + self.new(user["id"],user["name"],user["real_name"],user["profile"]["status_text"],user["profile"]["status_emoji"]) + + end + end +end \ No newline at end of file diff --git a/lib/verification.rb b/lib/verification.rb new file mode 100644 index 00000000..00da7d3b --- /dev/null +++ b/lib/verification.rb @@ -0,0 +1,24 @@ +require 'dotenv' +require 'httparty' +require 'awesome_print' + +Dotenv.load # allows access to ENV['VARIABLE_NAME'] + +CONVERSATIONS_LIST_URL = "https://slack.com/api/conversations.list" + +def verification + query = { + token: ENV["SLACK_TOKEN"] + } + + request = HTTParty.get(CONVERSATIONS_LIST_URL, query: query) + + if request.code != 200 || request["ok"] != true + return "API request failed with error code #{request.code} and #{request["error"]}." + else + channel_names = request["channels"].map { |channel| channel["name"] } + return channel_names + end +end + +ap verification diff --git a/lib/workspace.rb b/lib/workspace.rb new file mode 100644 index 00000000..affbd1df --- /dev/null +++ b/lib/workspace.rb @@ -0,0 +1,38 @@ +require_relative 'user' +require_relative 'channel' + +class Workspace + attr_reader :users, :channels + + def initialize + @users = [] + @channels = [] + end + + def load_channels + @channels = Channel.list_all + end + + def load_users + @users = User.list_all + end + + def select_channel(search_term) + return @channels.find{|channel| channel.name == search_term.downcase || channel.slack_id == search_term.upcase} + end + + def select_user(search_term) + return @users.find{|user| user.name == search_term.downcase || user.slack_id == search_term.upcase} + end + + def show_details(recipient) + if recipient + return recipient.details + else + return "Invalid recipient. Unable to display details" + end + end + +end + + diff --git a/test/cassettes/get_conversations_list.yml b/test/cassettes/get_conversations_list.yml new file mode 100644 index 00000000..9b8410b4 --- /dev/null +++ b/test/cassettes/get_conversations_list.yml @@ -0,0 +1,125 @@ +--- +http_interactions: +- request: + method: get + uri: https://slack.com/api/conversations.list?token= + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 00:26:15 GMT + Server: + - Apache + X-Slack-Req-Id: + - ddc4d7fbcbf0cc01d5e506cb586067cd + X-Oauth-Scopes: + - chat:write,channels:read,users:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - channels:read,groups:read,mpim:read,im:read,read + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '647' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-zxri,haproxy-edge-pdx-74gg + body: + encoding: ASCII-8BIT + string: '{"ok":true,"channels":[{"id":"C01BKRLQ4UF","name":"random","is_channel":true,"is_group":false,"is_im":false,"created":1601943301,"is_archived":false,"is_general":false,"unlinked":0,"name_normalized":"random","is_shared":false,"parent_conversation":null,"creator":"U01BXFBQ18D","is_ext_shared":false,"is_org_shared":false,"shared_team_ids":["T01BKRLPT7Z"],"pending_shared":[],"pending_connected_team_ids":[],"is_pending_ext_shared":false,"is_member":false,"is_private":false,"is_mpim":false,"topic":{"value":"","creator":"","last_set":0},"purpose":{"value":"This + channel is for... well, everything else. It\u2019s a place for team jokes, + spur-of-the-moment ideas, and funny GIFs. Go wild!","creator":"U01BXFBQ18D","last_set":1601943301},"previous_names":[],"num_members":3},{"id":"C01BXFENUR3","name":"slackcli","is_channel":true,"is_group":false,"is_im":false,"created":1601943445,"is_archived":false,"is_general":false,"unlinked":0,"name_normalized":"slackcli","is_shared":false,"parent_conversation":null,"creator":"U01BXFBQ18D","is_ext_shared":false,"is_org_shared":false,"shared_team_ids":["T01BKRLPT7Z"],"pending_shared":[],"pending_connected_team_ids":[],"is_pending_ext_shared":false,"is_member":false,"is_private":false,"is_mpim":false,"topic":{"value":"","creator":"","last_set":0},"purpose":{"value":"This + *channel* is for working on a project. Hold meetings, share docs, and make + decisions together with your team.","creator":"U01BXFBQ18D","last_set":1601943445},"previous_names":[],"num_members":2},{"id":"C01CD723J0H","name":"general","is_channel":true,"is_group":false,"is_im":false,"created":1601943301,"is_archived":false,"is_general":true,"unlinked":0,"name_normalized":"general","is_shared":false,"parent_conversation":null,"creator":"U01BXFBQ18D","is_ext_shared":false,"is_org_shared":false,"shared_team_ids":["T01BKRLPT7Z"],"pending_shared":[],"pending_connected_team_ids":[],"is_pending_ext_shared":false,"is_member":false,"is_private":false,"is_mpim":false,"topic":{"value":"","creator":"","last_set":0},"purpose":{"value":"This + is the one channel that will always include everyone. It\u2019s a great spot + for announcements and team-wide conversations.","creator":"U01BXFBQ18D","last_set":1601943301},"previous_names":[],"num_members":2}],"response_metadata":{"next_cursor":""}}' + recorded_at: Thu, 08 Oct 2020 00:26:15 GMT +- request: + method: get + uri: https://slack.com/api/conversations.list?token=unauthed%20test%20token + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 02:05:37 GMT + Server: + - Apache + X-Slack-Req-Id: + - 199aad22c97ec70e85dba73240486a9d + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + X-Slack-Backend: + - r + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Content-Length: + - '55' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-u1v1,haproxy-edge-pdx-mprq + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"invalid_auth"}' + recorded_at: Thu, 08 Oct 2020 02:05:37 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/get_conversations_list_--_bad_token.yml b/test/cassettes/get_conversations_list_--_bad_token.yml new file mode 100644 index 00000000..12c60d63 --- /dev/null +++ b/test/cassettes/get_conversations_list_--_bad_token.yml @@ -0,0 +1,56 @@ +--- +http_interactions: +- request: + method: get + uri: https://slack.com/api/conversations.list?token=unauthed%20test%20token + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 21:39:45 GMT + Server: + - Apache + X-Slack-Req-Id: + - 6b79dee0178048fc8eb716792ca19601 + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + X-Slack-Backend: + - r + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Content-Length: + - '55' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-sd3m,haproxy-edge-pdx-rqgu + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"invalid_auth"}' + recorded_at: Thu, 08 Oct 2020 21:39:45 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/get_users_list.yml b/test/cassettes/get_users_list.yml new file mode 100644 index 00000000..29d40ba8 --- /dev/null +++ b/test/cassettes/get_users_list.yml @@ -0,0 +1,184 @@ +--- +http_interactions: +- request: + method: get + uri: https://slack.com/api/users.list?token= + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Wed, 07 Oct 2020 23:43:52 GMT + Server: + - Apache + X-Slack-Req-Id: + - 857645eedae3f8610bd5f65a346c635d + X-Oauth-Scopes: + - chat:write,channels:read,users:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - users:read + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '1319' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-z9gt,haproxy-edge-pdx-tfuw + body: + encoding: ASCII-8BIT + string: '{"ok":true,"members":[{"id":"USLACKBOT","team_id":"T01BKRLPT7Z","name":"slackbot","deleted":false,"color":"757575","real_name":"Slackbot","tz":"America\/Los_Angeles","tz_label":"Pacific + Daylight Time","tz_offset":-25200,"profile":{"title":"","phone":"","skype":"","real_name":"Slackbot","real_name_normalized":"Slackbot","display_name":"Slackbot","display_name_normalized":"Slackbot","fields":null,"status_text":"","status_emoji":"","status_expiration":0,"avatar_hash":"sv41d8cd98f0","always_active":true,"first_name":"slackbot","last_name":"","image_24":"https:\/\/a.slack-edge.com\/80588\/img\/slackbot_24.png","image_32":"https:\/\/a.slack-edge.com\/80588\/img\/slackbot_32.png","image_48":"https:\/\/a.slack-edge.com\/80588\/img\/slackbot_48.png","image_72":"https:\/\/a.slack-edge.com\/80588\/img\/slackbot_72.png","image_192":"https:\/\/a.slack-edge.com\/80588\/marketing\/img\/avatars\/slackbot\/avatar-slackbot.png","image_512":"https:\/\/a.slack-edge.com\/80588\/img\/slackbot_512.png","status_text_canonical":"","team":"T01BKRLPT7Z"},"is_admin":false,"is_owner":false,"is_primary_owner":false,"is_restricted":false,"is_ultra_restricted":false,"is_bot":false,"is_app_user":false,"updated":0},{"id":"U01BXFBQ18D","team_id":"T01BKRLPT7Z","name":"gomezrc1220","deleted":false,"color":"9f69e7","real_name":"Rachael + Gomez","tz":"America\/Los_Angeles","tz_label":"Pacific Daylight Time","tz_offset":-25200,"profile":{"title":"","phone":"","skype":"","real_name":"Rachael + Gomez","real_name_normalized":"Rachael Gomez","display_name":"","display_name_normalized":"","fields":null,"status_text":"","status_emoji":"","status_expiration":0,"avatar_hash":"4b6270619864","image_original":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_original.png","is_custom_image":true,"image_24":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_24.png","image_32":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_32.png","image_48":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_48.png","image_72":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_72.png","image_192":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_192.png","image_512":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_512.png","image_1024":"https:\/\/avatars.slack-edge.com\/2020-10-05\/1393870876631_4b6270619864d83852e3_1024.png","status_text_canonical":"","team":"T01BKRLPT7Z"},"is_admin":true,"is_owner":true,"is_primary_owner":true,"is_restricted":false,"is_ultra_restricted":false,"is_bot":false,"is_app_user":false,"updated":1601943304},{"id":"U01C0JB1FB4","team_id":"T01BKRLPT7Z","name":"christabot","deleted":false,"color":"e7392d","real_name":"Christabot","tz":"America\/Los_Angeles","tz_label":"Pacific + Daylight Time","tz_offset":-25200,"profile":{"title":"","phone":"","skype":"","real_name":"Christabot","real_name_normalized":"Christabot","display_name":"","display_name_normalized":"","fields":null,"status_text":"","status_emoji":"","status_expiration":0,"avatar_hash":"g6bf8b9adec4","api_app_id":"A01C0J7RNGJ","always_active":false,"bot_id":"B01CQDPVC48","first_name":"Christabot","last_name":"","image_24":"https:\/\/secure.gravatar.com\/avatar\/6bf8b9adec4556f2274abbcadb932de0.jpg?s=24&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0022-24.png","image_32":"https:\/\/secure.gravatar.com\/avatar\/6bf8b9adec4556f2274abbcadb932de0.jpg?s=32&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0022-32.png","image_48":"https:\/\/secure.gravatar.com\/avatar\/6bf8b9adec4556f2274abbcadb932de0.jpg?s=48&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0022-48.png","image_72":"https:\/\/secure.gravatar.com\/avatar\/6bf8b9adec4556f2274abbcadb932de0.jpg?s=72&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0022-72.png","image_192":"https:\/\/secure.gravatar.com\/avatar\/6bf8b9adec4556f2274abbcadb932de0.jpg?s=192&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0022-192.png","image_512":"https:\/\/secure.gravatar.com\/avatar\/6bf8b9adec4556f2274abbcadb932de0.jpg?s=512&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0022-512.png","status_text_canonical":"","team":"T01BKRLPT7Z"},"is_admin":false,"is_owner":false,"is_primary_owner":false,"is_restricted":false,"is_ultra_restricted":false,"is_bot":true,"is_app_user":false,"updated":1602099127},{"id":"U01C6PPQXJQ","team_id":"T01BKRLPT7Z","name":"christabel.escarez","deleted":false,"color":"4bbe2e","real_name":"Christabel + Sebastian","tz":"America\/Los_Angeles","tz_label":"Pacific Daylight Time","tz_offset":-25200,"profile":{"title":"","phone":"","skype":"","real_name":"Christabel + Sebastian","real_name_normalized":"Christabel Sebastian","display_name":"Christabel + Sebastian","display_name_normalized":"Christabel Sebastian","fields":null,"status_text":"vibin + ~~~","status_emoji":":palm_tree:","status_expiration":0,"avatar_hash":"ged110857fb2","image_24":"https:\/\/secure.gravatar.com\/avatar\/ed110857fb2730f2e5016f61e8846f90.jpg?s=24&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0025-24.png","image_32":"https:\/\/secure.gravatar.com\/avatar\/ed110857fb2730f2e5016f61e8846f90.jpg?s=32&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0025-32.png","image_48":"https:\/\/secure.gravatar.com\/avatar\/ed110857fb2730f2e5016f61e8846f90.jpg?s=48&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0025-48.png","image_72":"https:\/\/secure.gravatar.com\/avatar\/ed110857fb2730f2e5016f61e8846f90.jpg?s=72&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0025-72.png","image_192":"https:\/\/secure.gravatar.com\/avatar\/ed110857fb2730f2e5016f61e8846f90.jpg?s=192&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0025-192.png","image_512":"https:\/\/secure.gravatar.com\/avatar\/ed110857fb2730f2e5016f61e8846f90.jpg?s=512&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0025-512.png","status_text_canonical":"","team":"T01BKRLPT7Z"},"is_admin":false,"is_owner":false,"is_primary_owner":false,"is_restricted":false,"is_ultra_restricted":false,"is_bot":false,"is_app_user":false,"updated":1602113813},{"id":"U01C6PZLEBW","team_id":"T01BKRLPT7Z","name":"waterrachaelapi_proje","deleted":false,"color":"3c989f","real_name":"Water-Rachael-API + Project","tz":"America\/Los_Angeles","tz_label":"Pacific Daylight Time","tz_offset":-25200,"profile":{"title":"","phone":"","skype":"","real_name":"Water-Rachael-API + Project","real_name_normalized":"Water-Rachael-API Project","display_name":"","display_name_normalized":"","fields":null,"status_text":"","status_emoji":"","status_expiration":0,"avatar_hash":"g500d535fa7d","api_app_id":"A01BTS37RQE","always_active":false,"bot_id":"B01BXFQKZ4M","image_24":"https:\/\/secure.gravatar.com\/avatar\/500d535fa7d1f82f70a6864ed14df800.jpg?s=24&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0018-24.png","image_32":"https:\/\/secure.gravatar.com\/avatar\/500d535fa7d1f82f70a6864ed14df800.jpg?s=32&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0018-32.png","image_48":"https:\/\/secure.gravatar.com\/avatar\/500d535fa7d1f82f70a6864ed14df800.jpg?s=48&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0018-48.png","image_72":"https:\/\/secure.gravatar.com\/avatar\/500d535fa7d1f82f70a6864ed14df800.jpg?s=72&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0018-72.png","image_192":"https:\/\/secure.gravatar.com\/avatar\/500d535fa7d1f82f70a6864ed14df800.jpg?s=192&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0018-192.png","image_512":"https:\/\/secure.gravatar.com\/avatar\/500d535fa7d1f82f70a6864ed14df800.jpg?s=512&d=https%3A%2F%2Fa.slack-edge.com%2Fdf10d%2Fimg%2Favatars%2Fava_0018-512.png","status_text_canonical":"","team":"T01BKRLPT7Z"},"is_admin":false,"is_owner":false,"is_primary_owner":false,"is_restricted":false,"is_ultra_restricted":false,"is_bot":true,"is_app_user":false,"updated":1601943944}],"cache_ts":1602114232,"response_metadata":{"next_cursor":""}}' + recorded_at: Wed, 07 Oct 2020 23:43:52 GMT +- request: + method: get + uri: https://slack.com/api/users.list?token=unauthed%20test%20token + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Wed, 07 Oct 2020 23:44:56 GMT + Server: + - Apache + X-Slack-Req-Id: + - 5df70fa650ed849a1d6b53274ad8c901 + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + X-Slack-Backend: + - r + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Content-Length: + - '55' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-28oy,haproxy-edge-pdx-bm9l + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"invalid_auth"}' + recorded_at: Wed, 07 Oct 2020 23:44:56 GMT +- request: + method: get + uri: https://slack.com/api/users.list?token= + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 22:15:16 GMT + Server: + - Apache + X-Xss-Protection: + - '0' + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + X-Accepted-Oauth-Scopes: + - users:read + X-Slack-Req-Id: + - d9cd6ecdf095c383a71e7ebc644f46cf + X-Slack-Backend: + - r + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + X-Content-Type-Options: + - nosniff + Content-Length: + - '53' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-g9kt,haproxy-edge-pdx-herk + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"not_authed"}' + recorded_at: Thu, 08 Oct 2020 22:15:16 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/get_users_list_--_bad_token.yml b/test/cassettes/get_users_list_--_bad_token.yml new file mode 100644 index 00000000..db937462 --- /dev/null +++ b/test/cassettes/get_users_list_--_bad_token.yml @@ -0,0 +1,56 @@ +--- +http_interactions: +- request: + method: get + uri: https://slack.com/api/users.list?token=unauthed%20test%20token + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 21:39:44 GMT + Server: + - Apache + X-Slack-Req-Id: + - dbeaf7aa1cc28caae5059e989a9ad883 + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + X-Slack-Backend: + - r + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + X-Content-Type-Options: + - nosniff + X-Xss-Protection: + - '0' + Content-Length: + - '55' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-m88x,haproxy-edge-pdx-1g64 + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"invalid_auth"}' + recorded_at: Thu, 08 Oct 2020 21:39:44 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/post_message_--_bad_recipient.yml b/test/cassettes/post_message_--_bad_recipient.yml new file mode 100644 index 00000000..a5995850 --- /dev/null +++ b/test/cassettes/post_message_--_bad_recipient.yml @@ -0,0 +1,66 @@ +--- +http_interactions: +- request: + method: post + uri: https://slack.com/api/chat.postMessage + body: + encoding: UTF-8 + string: token=&channel=failure&text=Testing + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 21:10:51 GMT + Server: + - Apache + X-Slack-Req-Id: + - 7a44c2d729cbb20a2438d49080194867 + X-Oauth-Scopes: + - users:read,chat:write,channels:read,channels:history,im:history,im:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - chat:write + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '60' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-k2o1,haproxy-edge-pdx-333x + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"channel_not_found"}' + recorded_at: Thu, 08 Oct 2020 21:10:51 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/post_message_to_channel.yml b/test/cassettes/post_message_to_channel.yml new file mode 100644 index 00000000..0c8ca7d2 --- /dev/null +++ b/test/cassettes/post_message_to_channel.yml @@ -0,0 +1,122 @@ +--- +http_interactions: +- request: + method: post + uri: https://slack.com/api/chat.postMessage + body: + encoding: UTF-8 + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 18:15:00 GMT + Server: + - Apache + X-Xss-Protection: + - '0' + Referrer-Policy: + - no-referrer + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + X-Accepted-Oauth-Scopes: + - chat:write:bot + X-Slack-Req-Id: + - 97b1b915c8e4b9b6cf05a363259893c4 + X-Slack-Backend: + - r + Access-Control-Allow-Origin: + - "*" + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + X-Content-Type-Options: + - nosniff + Content-Length: + - '53' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-lo72,haproxy-edge-pdx-locq + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"not_authed"}' + recorded_at: Thu, 08 Oct 2020 18:15:00 GMT +- request: + method: post + uri: https://slack.com/api/chat.postMessage + body: + encoding: UTF-8 + string: token=&channel=C01BKRLQ4UF&text=Testing + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 18:46:24 GMT + Server: + - Apache + X-Slack-Req-Id: + - 370b27daada22e83a85bb43d44ec99e9 + X-Oauth-Scopes: + - users:read,chat:write,channels:read,channels:history,im:history,im:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - chat:write + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '335' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-75m7,haproxy-edge-pdx-tfuw + body: + encoding: ASCII-8BIT + string: '{"ok":true,"channel":"C01BKRLQ4UF","ts":"1602182784.001300","message":{"bot_id":"B01CQDPVC48","type":"message","text":"Testing","user":"U01C0JB1FB4","ts":"1602182784.001300","team":"T01BKRLPT7Z","bot_profile":{"id":"B01CQDPVC48","deleted":false,"name":"Water + - Christabel - Slack CLI","updated":1601943921,"app_id":"A01C0J7RNGJ","icons":{"image_36":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_36.png","image_48":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_48.png","image_72":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/service_72.png"},"team_id":"T01BKRLPT7Z"}}}' + recorded_at: Thu, 08 Oct 2020 18:46:24 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/post_message_to_channel_--_nil_message.yml b/test/cassettes/post_message_to_channel_--_nil_message.yml new file mode 100644 index 00000000..a600a669 --- /dev/null +++ b/test/cassettes/post_message_to_channel_--_nil_message.yml @@ -0,0 +1,66 @@ +--- +http_interactions: +- request: + method: post + uri: https://slack.com/api/chat.postMessage + body: + encoding: UTF-8 + string: token=&channel=C01BKRLQ4UF&text= + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 18:57:57 GMT + Server: + - Apache + X-Slack-Req-Id: + - 215b08c382410717dd96a4fc75f8984c + X-Oauth-Scopes: + - users:read,chat:write,channels:read,channels:history,im:history,im:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - chat:write + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '50' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-9kiv,haproxy-edge-pdx-k9dj + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"no_text"}' + recorded_at: Thu, 08 Oct 2020 18:57:57 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/post_message_to_user.yml b/test/cassettes/post_message_to_user.yml new file mode 100644 index 00000000..a5bcc91e --- /dev/null +++ b/test/cassettes/post_message_to_user.yml @@ -0,0 +1,67 @@ +--- +http_interactions: +- request: + method: post + uri: https://slack.com/api/chat.postMessage + body: + encoding: UTF-8 + string: token=&channel=U01C6PZLEBW&text=Testing + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 21:08:57 GMT + Server: + - Apache + X-Slack-Req-Id: + - 7ca785a5ffc3e5badcd49944d0fa2f9d + X-Oauth-Scopes: + - users:read,chat:write,channels:read,channels:history,im:history,im:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - chat:write + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '337' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-ot84,haproxy-edge-pdx-bivi + body: + encoding: ASCII-8BIT + string: '{"ok":true,"channel":"D01CF3F5WDS","ts":"1602191337.000300","message":{"bot_id":"B01CQDPVC48","type":"message","text":"Testing","user":"U01C0JB1FB4","ts":"1602191337.000300","team":"T01BKRLPT7Z","bot_profile":{"id":"B01CQDPVC48","deleted":false,"name":"Water + - Christabel - Slack CLI","updated":1601943921,"app_id":"A01C0J7RNGJ","icons":{"image_36":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_36.png","image_48":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/bot_48.png","image_72":"https:\/\/a.slack-edge.com\/80588\/img\/plugins\/app\/service_72.png"},"team_id":"T01BKRLPT7Z"}}}' + recorded_at: Thu, 08 Oct 2020 21:08:57 GMT +recorded_with: VCR 6.0.0 diff --git a/test/cassettes/post_message_to_user_--_nil_message.yml b/test/cassettes/post_message_to_user_--_nil_message.yml new file mode 100644 index 00000000..55277d98 --- /dev/null +++ b/test/cassettes/post_message_to_user_--_nil_message.yml @@ -0,0 +1,66 @@ +--- +http_interactions: +- request: + method: post + uri: https://slack.com/api/chat.postMessage + body: + encoding: UTF-8 + string: token=&channel=U01C6PZLEBW&text= + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Date: + - Thu, 08 Oct 2020 21:11:34 GMT + Server: + - Apache + X-Slack-Req-Id: + - c1b0951e50a72d66ec5e22394069349e + X-Oauth-Scopes: + - users:read,chat:write,channels:read,channels:history,im:history,im:read + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Slack-Backend: + - r + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + X-Accepted-Oauth-Scopes: + - chat:write + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Vary: + - Accept-Encoding + Pragma: + - no-cache + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + Content-Length: + - '50' + Content-Type: + - application/json; charset=utf-8 + X-Via: + - haproxy-www-vtee,haproxy-edge-pdx-1350 + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"no_text"}' + recorded_at: Thu, 08 Oct 2020 21:11:34 GMT +recorded_with: VCR 6.0.0 diff --git a/test/channel_test.rb b/test/channel_test.rb new file mode 100644 index 00000000..8b0a4b01 --- /dev/null +++ b/test/channel_test.rb @@ -0,0 +1,94 @@ +require_relative 'test_helper' +require_relative '../lib/channel' + +describe "Channel class" do + + describe "instantiation" do + + before do + @new_channel = Channel.new("some_id", "some_name", "some topic", 300) + end + + it "is an instance of Channel" do + expect(@new_channel).must_be_instance_of Channel + end + + it "establishes the base data structures when instantiated" do + [:slack_id, :name, :topic, :member_count].each do |keyword| + expect(@new_channel).must_respond_to keyword + end + + expect(@new_channel.slack_id).must_be_kind_of String + expect(@new_channel.name).must_be_kind_of String + expect(@new_channel.topic).must_be_kind_of String + expect(@new_channel.member_count).must_be_kind_of Integer + end + + end + + describe "self.get" do + + before do + @query = {token: ENV["SLACK_TOKEN"]} + end + + it "calls Slack API conversations.list" do + VCR.use_cassette("get conversations list") do + conversations = Channel.get(CONVERSATIONS_LIST_URL, query: @query) + + channel_names = conversations["channels"].map { |channel| channel["name"] } + + expect(conversations.body).wont_be_nil + expect(conversations).must_be_instance_of HTTParty::Response + + ["random", "slackcli", "general"].each do |keyword| + expect(channel_names.include?(keyword)).must_equal true + end + end + end + + it "will raise an exception if the search fails" do + VCR.use_cassette("get conversations list -- bad token") do + expect { + Channel.get(CONVERSATIONS_LIST_URL, query: {token: "unauthed test token"}) + }.must_raise ArgumentError + end + end + + end + + describe "details" do + before do + @new_channel = Channel.new("some_id", "some_name", "some topic", 300) + @details = @new_channel.details + end + + it "returns String" do + expect(@details).must_be_kind_of String + end + it "returns the correct string" do + expect(@details).must_equal "Channel id: some_id\nChannel name: some_name\nTopic: some topic\nNumber of members: 300" + end + + end + + describe "self.list_all" do + + before do + VCR.use_cassette("get conversations list") do + @channel_list = Channel.list_all + end + end + + it "populates the array" do + expect(@channel_list).wont_be_empty + end + + it "@channels is an array of Channel objects" do + expect(@channel_list).must_be_kind_of Array + expect(@channel_list.all? { |channel| channel.class == Channel }).must_equal true + end + + end + +end \ No newline at end of file diff --git a/test/recipient_test.rb b/test/recipient_test.rb new file mode 100644 index 00000000..7492058a --- /dev/null +++ b/test/recipient_test.rb @@ -0,0 +1,93 @@ +require_relative 'test_helper' +require_relative '../lib/recipient' + +describe "Recipient class" do + + describe "instantiation" do + + before do + @new_recipient = Recipient.new("some_id", "some_name") + end + + it "is an instance of Recipient" do + expect(@new_recipient).must_be_instance_of Recipient + end + + it "establishes the base data structures when instantiated" do + [:slack_id, :name].each do |keyword| + expect(@new_recipient).must_respond_to keyword + end + + expect(@new_recipient.slack_id).must_be_kind_of String + expect(@new_recipient.name).must_be_kind_of String + + end + + end + + + describe "details" do + before do + @new_recipient = Recipient.new("some_id", "some_name") + end + + it "raises an error" do + expect{@new_recipient.details}.must_raise NotImplementedError + end + end + + describe "self.list_all" do + it "raises an error" do + expect{Recipient.list_all}.must_raise NotImplementedError + end + end + + describe "send message" do + before do + @channel_recipient = Recipient.new("C01BKRLQ4UF", "random") + @user_recipient = Recipient.new("U01C6PZLEBW", "Rachael's bot") + @message = "Testing" + end + + it "sends a message to a channel" do + VCR.use_cassette("post message to channel") do + response = @channel_recipient.send_message(@message) + expect(response["ok"]).must_equal true + end + end + + it "sends a message to a user" do + VCR.use_cassette("post message to user") do + response = @user_recipient.send_message(@message) + expect(response["ok"]).must_equal true + end + + end + + it "expect error_message for bad recipient" do + VCR.use_cassette("post message -- bad recipient") do + bad_recipient = Recipient.new("failure", "still a failure") + expect { + bad_recipient.send_message(@message) + }.must_raise ArgumentError + end + end + + it "expect error_message for nil `text` to a channel" do + VCR.use_cassette("post message to channel -- nil message") do + expect { + @channel_recipient.send_message(nil) + }.must_raise ArgumentError + end + end + + it "expect error_message for nil `text` to a user" do + VCR.use_cassette("post message to user -- nil message") do + expect { + @user_recipient.send_message(nil) + }.must_raise ArgumentError + end + end + + end +end \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index 1fcf2bab..01aeb095 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,20 +2,21 @@ SimpleCov.start do add_filter 'test/' end - +require 'dotenv' require 'minitest' require 'minitest/autorun' require 'minitest/reporters' require 'minitest/skip_dsl' require 'vcr' +require 'httparty' +require "awesome_print" +# require_relative '../lib/workspace' +# require_relative '../lib/channel' +# require_relative '../lib/user' +Dotenv.load Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new -VCR.configure do |config| - config.cassette_library_dir = "test/cassettes" - config.hook_into :webmock -end - VCR.configure do |config| config.cassette_library_dir = "test/cassettes" # folder where casettes will be located config.hook_into :webmock # tie into this other tool called webmock @@ -24,6 +25,11 @@ :match_requests_on => [:method, :uri, :body], # The http method, URI and body of a request all need to match } + config.allow_http_connections_when_no_cassette = true #added by Rachael and Christabel to allow to HTTP Requests without cassettes + # Don't leave our token lying around in a cassette file. + config.filter_sensitive_data("") do + ENV["SLACK_TOKEN"] + end end diff --git a/test/user_test.rb b/test/user_test.rb new file mode 100644 index 00000000..2f839196 --- /dev/null +++ b/test/user_test.rb @@ -0,0 +1,96 @@ +require_relative 'test_helper' +require_relative '../lib/user' + +describe "User class" do + + describe "instantiation" do + + before do + @new_user = User.new("some_id", "some_name", "some_name", "blah", ":)") + end + + it "is an instance of User" do + expect(@new_user).must_be_instance_of User + end + + it "establishes the base data structures when instantiated" do + [:slack_id, :name, :real_name, :status_text, :status_emoji].each do |keyword| + expect(@new_user).must_respond_to keyword + end + + expect(@new_user.slack_id).must_be_kind_of String + expect(@new_user.name).must_be_kind_of String + expect(@new_user.real_name).must_be_kind_of String + expect(@new_user.status_text).must_be_kind_of String + expect(@new_user.status_emoji).must_be_kind_of String + end + + end + + describe "self.get" do + + before do + @query = {token: ENV["SLACK_TOKEN"]} + end + + it "calls Slack API users.list" do + VCR.use_cassette("get users list") do + users = User.get(USERS_LIST_URL, query: @query) + + user_names = users["members"].map { |user| user["name"] } + + expect(users.body).wont_be_nil + expect(users).must_be_instance_of HTTParty::Response + + ["slackbot", "gomezrc1220", "christabot", "christabel.escarez", "waterrachaelapi_proje"].each do |keyword| + expect(user_names.include?(keyword)).must_equal true + end + end + end + + it "will raise an exception if the search fails" do + VCR.use_cassette("get users list -- bad token") do + expect { + User.get(USERS_LIST_URL, query: {token: "unauthed test token"}) + }.must_raise ArgumentError + end + end + + end + + describe "details" do + before do + @new_user = User.new("some_id", "some_name", "some_name", "blah", ":)") + @details = @new_user.details + end + + it "returns String" do + expect(@details).must_be_kind_of String + end + + it "returns the correct string" do + expect(@details).must_equal "User id: some_id\nUsername: some_name\nReal name: some_name\nStatus text: blah\nStatus emoji: :)" + end + + end + + describe "self.list_all" do + + before do + VCR.use_cassette("get users list") do + @user_list = User.list_all + end + end + + it "populates the array" do + expect(@user_list).wont_be_empty + end + + it "@channels is an array of User objects" do + expect(@user_list).must_be_kind_of Array + expect(@user_list.all? { |user| user.class == User }).must_equal true + end + + end + +end diff --git a/test/workspace_test.rb b/test/workspace_test.rb new file mode 100644 index 00000000..1502f8e6 --- /dev/null +++ b/test/workspace_test.rb @@ -0,0 +1,114 @@ +require_relative 'test_helper' +require_relative '../lib/workspace' + +# Is it most appropriate to create a whole set of false test data? Even for APIs??? + +describe "workspace class" do + + describe "workspace instantiation" do + before do + @new_workspace = Workspace.new + end + + it "is an instance of workspace" do + expect(@new_workspace).must_be_instance_of Workspace + end + + it "establishes the base data structures when instantiated" do + [:users, :channels].each do |keyword| + expect(@new_workspace).must_respond_to keyword + end + + expect(@new_workspace.users).must_be_kind_of Array + expect(@new_workspace.channels).must_be_kind_of Array + end + + end + describe "load channels" do + before do + VCR.use_cassette("get conversations list") do + @new_workspace = Workspace.new + @new_workspace.load_channels + end + end + it "populates the @channels instance variable" do + expect(@new_workspace.channels).wont_be_empty + end + end + + describe "load users" do + before do + VCR.use_cassette("get users list") do + @new_workspace = Workspace.new + @new_workspace.load_users + end + end + it "populates the @users instance variable" do + expect(@new_workspace.users).wont_be_empty + end + end + + describe "select channel" do + before do + VCR.use_cassette("get conversations list") do + @new_workspace = Workspace.new + @new_workspace.load_channels + end + end + it "returns a channel object" do + found_channel = @new_workspace.select_channel("random") + expect(found_channel).must_be_kind_of Channel + end + it "returns nil if object not found" do + not_found_channel = @new_workspace.select_channel("bloop") + expect(not_found_channel).must_be_nil + end + end + + describe "select user" do + before do + VCR.use_cassette("get users list") do + @new_workspace = Workspace.new + @new_workspace.load_users + end + end + it "returns a user object" do + found_user = @new_workspace.select_user("slackbot") + expect(found_user).must_be_kind_of User + end + it "returns nil if object not found" do + not_found_user = @new_workspace.select_user("bloop") + expect(not_found_user).must_be_nil + end + end + + describe "show details" do + before do + @new_workspace = Workspace.new + VCR.use_cassette("get users list") do + @new_workspace.load_users + end + VCR.use_cassette("get conversations list") do + @new_workspace.load_channels + end + end + it "returns String for user object" do + found_user = @new_workspace.select_user("slackbot") + + expect(@new_workspace.show_details(found_user)).must_be_kind_of String + end + it "returns String for channel object" do + found_channel = @new_workspace.select_channel("random") + + expect(@new_workspace.show_details(found_channel)).must_be_kind_of String + end + it "returns message for no details available" do + found_channel = @new_workspace.select_channel("nope") + expect(@new_workspace.show_details(found_channel)).must_equal "Invalid recipient. Unable to display details" + end + it "returns message for no details available" do + found_user = @new_workspace.select_user("nope2.0") + expect(@new_workspace.show_details(found_user)).must_equal "Invalid recipient. Unable to display details" + end + end +end \ No newline at end of file