Skip to content

Instantly share code, notes, and snippets.

@fpaint
Created October 3, 2023 07:19
Show Gist options
  • Select an option

  • Save fpaint/eadb52de55f72670f7c7c22e77c8b149 to your computer and use it in GitHub Desktop.

Select an option

Save fpaint/eadb52de55f72670f7c7c22e77c8b149 to your computer and use it in GitHub Desktop.
My tiny slack client
# frozen_string_literal: true
class Slack::ApiClient
class Error < StandardError; end
API_URL = 'https://slack.com/api'
attr_reader :token
def initialize(token = nil)
@token = token
end
def post_request(endpoint, payload = {})
response = RestClient.post "#{API_URL}/#{endpoint}", payload.merge(token: token)
data = JSON.parse response
if data['ok']
data
else
raise Error, data['error']
end
end
def get_request(endpoint, payload)
response = RestClient.get "#{API_URL}/#{endpoint}", payload.merge(token: token)
JSON.parse response
end
def channel(channel_id)
Slack::Channel.new(self, channel_id)
end
end
# frozen_string_literal: true
require 'test_helper'
describe Slack::ApiClient do
let(:token) { 'some_secret_api_token' }
let(:client) { Slack::ApiClient.new(token) }
describe '#post_request' do
let(:data) { {'param' => 'value'} }
let(:good_response) { data.merge({'ok' => true}) }
let(:bad_response) { data.merge({'ok' => false, 'error' => 'wrong_request'}) }
it 'should send http with token and return response' do
RestClient.expects(:post).returns(good_response.to_json).with do |url, payload|
assert_equal 'https://slack.com/api/chat.method', url
assert_equal({token: token, text: 'the text param'}, payload)
end
result = client.post_request('chat.method', {text: 'the text param'})
assert result
assert_equal 'value', result['param']
end
it 'should allow to send get requests' do
RestClient.expects(:get).returns(good_response.to_json).with do |url, payload|
assert_equal 'https://slack.com/api/chat.method', url
assert_equal({token: token, text: 'the text param'}, payload)
end
result = client.get_request('chat.method', {text: 'the text param'})
assert result
assert_equal 'value', result['param']
end
it 'should raise proper error' do
RestClient.expects(:post).returns(bad_response.to_json)
assert_raises Slack::ApiClient::Error, 'wrong_request' do
client.post_request('chat.method', {text: 'the text param'})
end
end
end
end
# frozen_string_literal: true
class Slack::Channel
def initialize(client, channel_id)
@client = client
@channel_id = channel_id
end
def message(timestamp)
Slack::Message.new(@client, @channel_id, timestamp)
end
def create_message(text)
payload = {channel: @channel_id, as_user: true, text: text}
result = @client.post_request 'chat.postMessage', payload
raise ArgumentError, result['error'] if result['ok'] == false
result['ts']
end
def has_message?(timestamp)
result = @client.get_request('chat.getPermalink', channel: @channel_id, message_ts: timestamp)
raise ArgumentError, result['error'] if result['ok'] == false && result['error'] != 'message_not_found'
result['ok']
end
end
# frozen_string_literal: true
require 'test_helper'
describe Slack::Channel do
let(:text) { 'Here is a message for you' }
let(:channel_id) { 'C123456' }
let(:msg_ts) { '1503435956.000247' }
let(:client) { mock('SlackApi') }
let(:channel) { Slack::Channel.new(client, channel_id) }
describe 'posting message' do
let(:response) do
{
'ok' => true,
'channel' => channel_id,
'ts' => msg_ts,
'message' => {
'text' => text,
'type' => 'message'
}
}
end
it 'should send request and return message timestamp' do
client.expects(:post_request).returns(response).with do |endpoint, payload|
assert_equal 'chat.postMessage', endpoint
assert_equal({channel: channel_id, as_user: true, text: text}, payload)
end
result = channel.create_message(text)
assert_equal msg_ts, result
end
end
describe 'checking message exists' do
let(:response) do
{
'ok' => true,
'channel' => channel_id,
'permalink' => 'https://myslack.slack.com/archives/C123456/p135854651500008'
}
end
it 'should return true' do
client.expects(:get_request).returns(response).with do |endpoint, payload|
assert_equal 'chat.getPermalink', endpoint
assert_equal({channel: channel_id, message_ts: msg_ts}, payload)
end
result = channel.has_message?(msg_ts)
assert result
end
end
end
# frozen_string_literal: true
class Slack::Message
def initialize(client, channel_id, timestamp)
@client = client
@channel_id = channel_id
@timestamp = timestamp
end
def comment(text)
payload = {channel: @channel_id, thread_ts: @timestamp, as_user: true, text: text}
@client.post_request 'chat.postMessage', payload
end
def delete
@client.post_request 'chat.delete', channel: @channel_id, ts: @timestamp, as_user: true
end
def add_reaction(emoji_name)
@client.post_request 'reactions.add', channel: @channel_id, timestamp: @timestamp, name: emoji_name
rescue Slack::ApiClient::Error => e
raise e unless e.message.in? %w[message_not_found already_reacted]
end
def remove_reaction(emoji_name)
@client.post_request 'reactions.remove', channel: @channel_id, timestamp: @timestamp, name: emoji_name
rescue Slack::ApiClient::Error => e
raise e unless e.message.in? %w[message_not_found no_reaction]
end
end
# frozen_string_literal: true
require 'test_helper'
describe Slack::Message do
let(:text) { 'Here is a message for you' }
let(:channel_id) { 'C123456' }
let(:msg_ts) { '1503435956.000247' }
let(:client) { Slack::ApiClient.new }
let(:msg) { Slack::Message.new(client, channel_id, msg_ts) }
let(:good_response) do
{'ok' => true}
end
let(:bad_response) do
{
'ok' => false,
'error' => expected_error
}
end
describe 'adding comment' do
it 'should send request' do
client.expects(:post_request).returns(good_response).with do |endpoint, payload|
assert_equal 'chat.postMessage', endpoint
assert_equal({channel: channel_id, as_user: true, thread_ts: msg_ts, text: text}, payload)
end
msg.comment(text)
end
end
describe 'deleting message' do
it 'should send request' do
client.expects(:post_request).returns(good_response).with do |endpoint, payload|
assert_equal 'chat.delete', endpoint
assert_equal({channel: channel_id, as_user: true, ts: msg_ts}, payload)
end
msg.delete
end
end
describe 'add reaction' do
let(:emoji) { 'heavy_check_mark' }
it 'should send request' do
client.expects(:post_request).returns(good_response).with do |endpoint, payload|
assert_equal 'reactions.add', endpoint
assert_equal({channel: channel_id, timestamp: msg_ts, name: emoji}, payload)
end
msg.add_reaction(emoji)
end
describe 'errors' do
let(:expected_error) { 'invalid_name' }
it 'should raise an error if api call fails' do
RestClient.expects(:post).returns(bad_response.to_json)
assert_raises Slack::ApiClient::Error, expected_error do
msg.add_reaction(emoji)
end
end
describe 'specific error' do
let(:expected_error) { 'already_reacted' }
it 'should not raise on specific errors' do
RestClient.expects(:post).returns(bad_response.to_json)
msg.add_reaction(emoji)
end
end
end
end
describe 'remove reaction' do
let(:emoji) { 'heavy_check_mark' }
it 'should send request' do
client.expects(:post_request).returns(good_response).with do |endpoint, payload|
assert_equal 'reactions.remove', endpoint
assert_equal({channel: channel_id, timestamp: msg_ts, name: emoji}, payload)
end
msg.remove_reaction(emoji)
end
describe 'errors' do
let(:expected_error) { 'invalid_name' }
it 'should raise an error if api call fails' do
RestClient.expects(:post).returns(bad_response.to_json)
assert_raises Slack::ApiClient::Error, expected_error do
msg.remove_reaction(emoji)
end
end
describe 'specific error' do
let(:expected_error) { 'no_reaction' }
it 'should not raise on specific errors' do
RestClient.expects(:post).returns(bad_response.to_json)
msg.remove_reaction(emoji)
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment