├── .rspec ├── lib ├── slack.rb ├── slack_ruby_client.rb ├── slack │ ├── version.rb │ ├── real_time │ │ ├── models │ │ │ ├── im.rb │ │ │ ├── bot.rb │ │ │ ├── team.rb │ │ │ ├── user.rb │ │ │ ├── channel.rb │ │ │ ├── group.rb │ │ │ └── base.rb │ │ ├── api │ │ │ ├── templates │ │ │ │ └── event_handler.erb │ │ │ ├── message_id.rb │ │ │ ├── schema │ │ │ │ └── event.json │ │ │ ├── ping.rb │ │ │ ├── typing.rb │ │ │ └── message.rb │ │ ├── concurrency.rb │ │ ├── stores.rb │ │ ├── models.rb │ │ ├── stores │ │ │ └── base.rb │ │ ├── config.rb │ │ ├── concurrency │ │ │ ├── eventmachine.rb │ │ │ └── celluloid.rb │ │ └── socket.rb │ ├── web │ │ ├── api │ │ │ ├── templates │ │ │ │ ├── commands.erb │ │ │ │ ├── endpoints.erb │ │ │ │ ├── method_spec.erb │ │ │ │ ├── command.erb │ │ │ │ └── method.erb │ │ │ ├── mixins.rb │ │ │ ├── schema │ │ │ │ ├── group.json │ │ │ │ └── method.json │ │ │ ├── error.rb │ │ │ ├── mixins │ │ │ │ ├── users.search.json │ │ │ │ ├── users.id.json │ │ │ │ ├── groups.id.json │ │ │ │ ├── channels.id.json │ │ │ │ ├── users.id.rb │ │ │ │ ├── groups.id.rb │ │ │ │ ├── channels.id.rb │ │ │ │ └── users.search.rb │ │ │ ├── endpoints │ │ │ │ ├── emoji.rb │ │ │ │ ├── bots.rb │ │ │ │ ├── team_profile.rb │ │ │ │ ├── api.rb │ │ │ │ ├── presence.rb │ │ │ │ ├── rtm.rb │ │ │ │ ├── auth.rb │ │ │ │ ├── oauth.rb │ │ │ │ ├── users_profile.rb │ │ │ │ ├── usergroups_users.rb │ │ │ │ ├── team.rb │ │ │ │ ├── dnd.rb │ │ │ │ ├── stars.rb │ │ │ │ ├── pins.rb │ │ │ │ ├── search.rb │ │ │ │ ├── files_comments.rb │ │ │ │ └── reminders.rb │ │ │ ├── patches │ │ │ │ ├── chat.1.text-attachments-required.patch │ │ │ │ ├── chat.2.attachments-json.patch │ │ │ │ └── chat.3.update-attachments-support.patch │ │ │ └── endpoints.rb │ │ ├── faraday │ │ │ ├── response │ │ │ │ └── raise_error.rb │ │ │ ├── request.rb │ │ │ └── connection.rb │ │ ├── client.rb │ │ └── config.rb │ ├── logger.rb │ ├── messages │ │ ├── message.rb │ │ └── formatting.rb │ └── config.rb ├── tasks │ ├── git.rake │ ├── update.rake │ ├── real_time.rake │ └── web.rake └── slack-ruby-client.rb ├── Dangerfile ├── .gitignore ├── slack.png ├── examples ├── hi_real_time_async_celluloid │ ├── Procfile │ ├── Gemfile │ └── hi.rb ├── hi_real_time_async_eventmachine │ ├── Procfile │ ├── Gemfile │ └── hi.rb ├── hi_web │ ├── Gemfile │ ├── hi.gif │ └── hi.rb ├── new_ticket │ ├── Gemfile │ └── new_ticket.rb ├── hi_real_time │ ├── hi.gif │ ├── Gemfile │ └── hi.rb └── hi_real_time_and_web │ ├── hi.gif │ ├── Gemfile │ └── hi.rb ├── screenshots └── register-bot.png ├── .rubocop.yml ├── .gitmodules ├── spec ├── slack │ ├── version_spec.rb │ ├── web │ │ └── api │ │ │ ├── endpoints │ │ │ ├── api_spec.rb │ │ │ ├── bots_spec.rb │ │ │ ├── rtm_spec.rb │ │ │ ├── team_spec.rb │ │ │ ├── emoji_spec.rb │ │ │ ├── stars_spec.rb │ │ │ ├── team_profile_spec.rb │ │ │ ├── users_profile_spec.rb │ │ │ ├── custom_specs │ │ │ │ ├── channels_spec.rb │ │ │ │ ├── groups_spec.rb │ │ │ │ ├── auth_spec.rb │ │ │ │ ├── users_spec.rb │ │ │ │ └── chat_spec.rb │ │ │ ├── dnd_spec.rb │ │ │ ├── reactions_spec.rb │ │ │ ├── pins_spec.rb │ │ │ ├── search_spec.rb │ │ │ ├── oauth_spec.rb │ │ │ ├── usergroups_users_spec.rb │ │ │ ├── usergroups_spec.rb │ │ │ ├── im_spec.rb │ │ │ ├── mpim_spec.rb │ │ │ ├── files_spec.rb │ │ │ ├── reminders_spec.rb │ │ │ └── files_comments_spec.rb │ │ │ ├── error_spec.rb │ │ │ └── mixins │ │ │ ├── groups_spec.rb │ │ │ ├── channels_spec.rb │ │ │ └── users_spec.rb │ ├── config_spec.rb │ ├── real_time │ │ ├── store_spec.rb │ │ ├── api │ │ │ ├── ping_spec.rb │ │ │ ├── typing_spec.rb │ │ │ └── message_spec.rb │ │ ├── rtm_start_spec.rb │ │ ├── event_handlers │ │ │ ├── event_handlers_spec.rb │ │ │ ├── bot_spec.rb │ │ │ ├── im_spec.rb │ │ │ ├── user_spec.rb │ │ │ ├── team_spec.rb │ │ │ └── group_spec.rb │ │ └── concurrency │ │ │ ├── it_behaves_like_a_realtime_socket.rb │ │ │ ├── celluloid_spec.rb │ │ │ └── eventmachine_spec.rb │ ├── messages │ │ └── formatting_spec.rb │ └── slack_spec.rb ├── support │ ├── real_time │ │ ├── event.rb │ │ ├── concurrency │ │ │ └── mock.rb │ │ └── connected_client.rb │ ├── token.rb │ ├── vcr.rb │ └── queue_with_timeout.rb ├── spec_helper.rb └── fixtures │ └── slack │ └── web │ ├── auth_test_error.yml │ ├── auth_test_success.yml │ ├── groups_info.yml │ ├── 429_error.yml │ └── channels_info.yml ├── Gemfile ├── bin ├── commands │ ├── emoji.rb │ ├── bots.rb │ ├── api.rb │ ├── team_profile.rb │ ├── rtm.rb │ ├── oauth.rb │ ├── auth.rb │ ├── users_profile.rb │ ├── usergroups_users.rb │ ├── files_comments.rb │ ├── pins.rb │ ├── search.rb │ ├── reminders.rb │ ├── stars.rb │ ├── team.rb │ ├── dnd.rb │ ├── im.rb │ ├── mpim.rb │ ├── reactions.rb │ ├── usergroups.rb │ ├── users.rb │ └── files.rb ├── commands.rb └── slack ├── Rakefile ├── .travis.yml ├── LICENSE.md ├── slack-ruby-client.gemspec ├── RELEASING.md ├── .rubocop_todo.yml └── UPGRADING.md /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | -------------------------------------------------------------------------------- /lib/slack.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | -------------------------------------------------------------------------------- /lib/slack_ruby_client.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | -------------------------------------------------------------------------------- /Dangerfile: -------------------------------------------------------------------------------- 1 | # inherits from https://github.com/slack-ruby/danger 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | pkg 3 | Gemfile.lock 4 | .DS_Store 5 | .bundle 6 | -------------------------------------------------------------------------------- /lib/slack/version.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | VERSION = '0.7.7'.freeze 3 | end 4 | -------------------------------------------------------------------------------- /slack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workato/slack-ruby-client/master/slack.png -------------------------------------------------------------------------------- /examples/hi_real_time_async_celluloid/Procfile: -------------------------------------------------------------------------------- 1 | console: bundle exec ruby hi.rb 2 | 3 | -------------------------------------------------------------------------------- /examples/hi_real_time_async_eventmachine/Procfile: -------------------------------------------------------------------------------- 1 | console: bundle exec ruby hi.rb 2 | 3 | -------------------------------------------------------------------------------- /examples/hi_web/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'slack-ruby-client', path: '../..' 4 | -------------------------------------------------------------------------------- /examples/hi_web/hi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workato/slack-ruby-client/master/examples/hi_web/hi.gif -------------------------------------------------------------------------------- /examples/new_ticket/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'slack-ruby-client', path: '../..' 4 | -------------------------------------------------------------------------------- /examples/hi_real_time/hi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workato/slack-ruby-client/master/examples/hi_real_time/hi.gif -------------------------------------------------------------------------------- /screenshots/register-bot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workato/slack-ruby-client/master/screenshots/register-bot.png -------------------------------------------------------------------------------- /examples/hi_real_time_and_web/hi.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/workato/slack-ruby-client/master/examples/hi_real_time_and_web/hi.gif -------------------------------------------------------------------------------- /examples/hi_real_time_and_web/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'slack-ruby-client', path: '../..' 4 | 5 | gem 'faye-websocket' 6 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - vendor/**/* 4 | - lib/slack/web/api/slack-api-ref/**/* 5 | 6 | inherit_from: .rubocop_todo.yml 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/slack/web/api/slack-api-ref"] 2 | path = lib/slack/web/api/slack-api-ref 3 | url = git@github.com:dblock/slack-api-ref.git 4 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/im.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class Im < Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/bot.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class Bot < Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/team.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class Team < Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/user.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class User < Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/channel.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class Channel < Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/group.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class Group < Base 5 | end 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /spec/slack/version_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Slack do 4 | it 'has a version' do 5 | expect(Slack::VERSION).to_not be nil 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /examples/hi_real_time_async_eventmachine/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'slack-ruby-client', path: '../..' 4 | 5 | gem 'faye-websocket' 6 | gem 'foreman' 7 | -------------------------------------------------------------------------------- /lib/slack/web/api/templates/commands.erb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | <% files.each do |f| %> 4 | require 'commands/<%= f %>' 5 | <% end %> 6 | -------------------------------------------------------------------------------- /examples/hi_real_time/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'slack-ruby-client', path: '../..' 4 | 5 | gem 'celluloid-io', require: ['celluloid/current', 'celluloid/io'] 6 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins.rb: -------------------------------------------------------------------------------- 1 | require 'slack/web/api/mixins/channels.id' 2 | require 'slack/web/api/mixins/users.id' 3 | require 'slack/web/api/mixins/users.search' 4 | require 'slack/web/api/mixins/groups.id' 5 | -------------------------------------------------------------------------------- /examples/hi_real_time_async_celluloid/Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gem 'slack-ruby-client', path: '../..' 4 | 5 | gem 'celluloid-io', require: ['celluloid/current', 'celluloid/io'] 6 | gem 'foreman' 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'http://rubygems.org' 2 | 3 | gemspec 4 | 5 | gem ENV['CONCURRENCY'], require: false if ENV.key?('CONCURRENCY') 6 | gem 'picky' unless RUBY_PLATFORM == 'java' 7 | gem 'activesupport', '~> 4.0' 8 | gem 'danger', '~> 2.0' 9 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/api_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Api do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/bots_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Bots do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/rtm_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Rtm do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/team_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Team do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/emoji_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Emoji do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/stars_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Stars do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /spec/support/real_time/event.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | class Event 4 | attr_accessor :data 5 | 6 | def initialize(data) 7 | @data = data.to_json 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/team_profile_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::TeamProfile do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /lib/slack/real_time/models/base.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Models 4 | class Base < Hashie::Mash 5 | def presence 6 | super['presence'] 7 | end 8 | end 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/users_profile_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::UsersProfile do 6 | let(:client) { Slack::Web::Client.new } 7 | end 8 | -------------------------------------------------------------------------------- /lib/slack/real_time/api/templates/event_handler.erb: -------------------------------------------------------------------------------- 1 | # <%= desc %> 2 | # @see https://api.slack.com/events/<%= name %> 3 | # @see https://github.com/dblock/slack-api-ref/blob/master/events/<%= name %>.json 4 | # on :<%= name %> do |data| 5 | -------------------------------------------------------------------------------- /lib/slack/web/api/schema/group.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "required": [ 4 | "name" 5 | ], 6 | "properties": { 7 | "name": { 8 | "type": "string" 9 | }, 10 | "desc": { 11 | "type": "string" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/tasks/git.rake: -------------------------------------------------------------------------------- 1 | namespace :slack do 2 | # update slack-api-ref from https://github.com/dblock/slack-api-ref 3 | task :git_update do 4 | sh 'git submodule update --init --recursive' 5 | sh 'git submodule foreach git pull origin master' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /lib/slack/real_time/concurrency.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Concurrency 4 | autoload :Eventmachine, 'slack/real_time/concurrency/eventmachine' 5 | autoload :Celluloid, 'slack/real_time/concurrency/celluloid' 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /lib/slack/real_time/stores.rb: -------------------------------------------------------------------------------- 1 | require 'slack/real_time/stores/base' 2 | require 'slack/real_time/stores/starter' 3 | require 'slack/real_time/stores/store' 4 | 5 | module Slack 6 | module RealTime 7 | class Store < Stores::Store 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /spec/support/token.rb: -------------------------------------------------------------------------------- 1 | RSpec.configure do |config| 2 | config.before do 3 | @old_token = Slack::Config.token 4 | end 5 | config.after do 6 | Slack::Config.token = @old_token 7 | Slack::Web::Config.reset 8 | Slack::RealTime::Config.reset 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/slack/logger.rb: -------------------------------------------------------------------------------- 1 | require 'logger' 2 | 3 | module Slack 4 | class Logger < ::Logger 5 | def self.default 6 | @logger ||= begin 7 | logger = new STDOUT 8 | logger.level = Logger::WARN 9 | logger 10 | end 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/slack/real_time/api/message_id.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Api 4 | module MessageId 5 | private 6 | 7 | def next_id 8 | @next_id ||= 0 9 | @next_id += 1 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/support/vcr.rb: -------------------------------------------------------------------------------- 1 | require 'vcr' 2 | require 'webmock/rspec' 3 | 4 | VCR.configure do |config| 5 | config.cassette_library_dir = 'spec/fixtures/slack' 6 | config.hook_into :webmock 7 | config.default_cassette_options = { record: :new_episodes } 8 | config.configure_rspec_metadata! 9 | end 10 | -------------------------------------------------------------------------------- /lib/tasks/update.rake: -------------------------------------------------------------------------------- 1 | namespace :slack do 2 | namespace :api do 3 | desc 'Auto-generate automatic portions of the Slack API client.' 4 | task :update do 5 | Rake::Task['slack:real_time:api:update'].invoke 6 | Rake::Task['slack:web:api:update'].invoke 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /lib/slack/real_time/models.rb: -------------------------------------------------------------------------------- 1 | require 'slack/real_time/models/base' 2 | require 'slack/real_time/models/user' 3 | require 'slack/real_time/models/bot' 4 | require 'slack/real_time/models/channel' 5 | require 'slack/real_time/models/group' 6 | require 'slack/real_time/models/team' 7 | require 'slack/real_time/models/im' 8 | -------------------------------------------------------------------------------- /lib/slack/web/api/error.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Api 4 | class Error < ::Faraday::Error 5 | attr_reader :response 6 | 7 | def initialize(message, response = nil) 8 | @response = response 9 | super message 10 | end 11 | end 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/slack/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Slack::Config do 4 | describe '#configure' do 5 | before do 6 | Slack.configure do |config| 7 | config.token = 'a token' 8 | end 9 | end 10 | it 'sets token' do 11 | expect(Slack.config.token).to eq 'a token' 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/slack/messages/message.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Messages 3 | class Message < Hashie::Mash 4 | def presence 5 | super['presence'] 6 | end 7 | 8 | def to_s 9 | keys.sort_by(&:to_s).map do |key| 10 | "#{key}=#{self[key]}" 11 | end.join(', ') 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /examples/hi_web/hi.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | 3 | Slack.configure do |config| 4 | config.token = ENV['SLACK_API_TOKEN'] 5 | fail 'Missing ENV[SLACK_API_TOKEN]!' unless config.token 6 | end 7 | 8 | client = Slack::Web::Client.new 9 | 10 | client.auth_test 11 | 12 | client.chat_postMessage(channel: '#general', text: 'Hello World', as_user: true) 13 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..')) 2 | 3 | require 'rubygems' 4 | require 'rspec' 5 | 6 | require 'slack-ruby-client' 7 | 8 | Dir[File.join(File.dirname(__FILE__), 'support', '**/*.rb')].each do |file| 9 | require file 10 | end 11 | 12 | Slack.configure do |config| 13 | config.token = ENV['SLACK_API_TOKEN'] 14 | end 15 | -------------------------------------------------------------------------------- /spec/slack/real_time/store_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Store do 4 | it 'can be initialized with an empty hash' do 5 | store = Slack::RealTime::Store.new(Hashie::Mash.new) 6 | expect(store.self).to be nil 7 | expect(store.groups.count).to eq 0 8 | expect(store.team).to be nil 9 | expect(store.teams.count).to eq 0 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/custom_specs/channels_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Endpoints::Channels do 4 | let(:client) { Slack::Web::Client.new } 5 | context 'channels' do 6 | it 'info', vcr: { cassette_name: 'web/channels_info' } do 7 | json = client.channels_info(channel: '#general') 8 | expect(json.channel.name).to eq 'general' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /bin/commands/emoji.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Emoji methods.' 4 | command 'emoji' do |g| 5 | g.desc 'This method lists the custom emoji for a team.' 6 | g.long_desc %( This method lists the custom emoji for a team. ) 7 | g.command 'list' do |c| 8 | c.action do |_global_options, options, _args| 9 | puts JSON.dump($client.emoji_list(options)) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/slack/real_time/api/schema/event.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "required": [ 4 | "name", 5 | "desc" 6 | ], 7 | "properties": { 8 | "name": { 9 | "type": "string" 10 | }, 11 | "desc": { 12 | "type": "string" 13 | }, 14 | "long_desc": { 15 | "type": "string" 16 | }, 17 | "example": { 18 | "type": "object", 19 | "default": {} 20 | } 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /lib/slack/config.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Config 3 | extend self 4 | 5 | attr_accessor :token 6 | attr_accessor :logger 7 | 8 | def reset 9 | self.token = nil 10 | self.logger = nil 11 | end 12 | 13 | reset 14 | end 15 | 16 | class << self 17 | def configure 18 | block_given? ? yield(Config) : Config 19 | end 20 | 21 | def config 22 | Config 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/dnd_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Dnd do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'dnd_setSnooze' do 8 | it 'requires num_minutes' do 9 | expect { client.dnd_setSnooze }.to raise_error ArgumentError, /Required arguments :num_minutes missing/ 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/slack/web/faraday/response/raise_error.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Faraday 4 | module Response 5 | class RaiseError < ::Faraday::Response::Middleware 6 | def on_complete(env) 7 | body = env.body 8 | return if body['ok'] 9 | fail Slack::Web::Api::Error.new(body['error'], env.response) 10 | end 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/custom_specs/groups_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Endpoints::Groups do 4 | let(:client) { Slack::Web::Client.new } 5 | context 'groups' do 6 | it 'info', vcr: { cassette_name: 'web/groups_info' } do 7 | json = client.groups_info(channel: '#mpdm-dblock--rubybot--player1-1') 8 | expect(json.group.name).to eq 'mpdm-dblock--rubybot--player1-1' 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /spec/slack/real_time/api/ping_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | describe '#ping' do 7 | before do 8 | allow(client).to receive(:next_id).and_return(42) 9 | end 10 | it 'sends message' do 11 | expect(socket).to receive(:send_data).with({ type: 'ping', id: 42 }.to_json) 12 | client.ping 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /bin/commands/bots.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Bots methods.' 4 | command 'bots' do |g| 5 | g.desc 'This method returns information about a bot user.' 6 | g.long_desc %( This method returns information about a bot user. ) 7 | g.command 'info' do |c| 8 | c.flag 'bot', desc: 'Bot user to get info on.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.bots_info(options)) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/slack/web/api/error_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Error do 4 | let(:client) { Slack::Web::Client.new } 5 | it 'provides access to the response object', vcr: { cassette_name: 'web/auth_test_error' } do 6 | begin 7 | client.auth_test 8 | fail 'Expected to receive Slack::Web::Api::Error.' 9 | rescue Slack::Web::Api::Error => e 10 | expect(e.response).to_not be_nil 11 | expect(e.response.status).to eq 200 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/slack/real_time/rtm_start_spec.rb: -------------------------------------------------------------------------------- 1 | # require 'spec_helper' 2 | 3 | # 4 | # to re-record a rtm_start fixture run with 5 | # SLACK_API_TOKEN=... CONCURRENCY=faye-websocket rspec spec/slack/real_time/rtm_start_spec.rb 6 | # edit rtm_start.yml and remove the token, fix wss:// path (run specs, fix failures) 7 | # 8 | 9 | # RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 10 | # it 'connects' do 11 | # Slack::Web::Client.new.rtm_start(mpim_aware: true) 12 | # end 13 | # end 14 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | require 'bundler/gem_tasks' 4 | 5 | Bundler.setup :default, :development 6 | 7 | require 'rspec/core' 8 | require 'rspec/core/rake_task' 9 | 10 | RSpec::Core::RakeTask.new(:spec) do |spec| 11 | spec.pattern = FileList['spec/**/*_spec.rb'] 12 | end 13 | 14 | require 'rubocop/rake_task' 15 | RuboCop::RakeTask.new 16 | 17 | task default: [:rubocop, :spec] 18 | 19 | load 'tasks/git.rake' 20 | load 'tasks/web.rake' 21 | load 'tasks/real_time.rake' 22 | load 'tasks/update.rake' 23 | -------------------------------------------------------------------------------- /bin/commands/api.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Api methods.' 4 | command 'api' do |g| 5 | g.desc 'This method helps you test your calling code.' 6 | g.long_desc %( This method helps you test your calling code. ) 7 | g.command 'test' do |c| 8 | c.flag 'error', desc: 'Error response to return.' 9 | c.flag 'foo', desc: 'example property to return.' 10 | c.action do |_global_options, options, _args| 11 | puts JSON.dump($client.api_test(options)) 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /spec/slack/real_time/api/typing_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | describe '#typing' do 7 | before do 8 | allow(client).to receive(:next_id).and_return(42) 9 | end 10 | it 'sends a typing indicator' do 11 | expect(socket).to receive(:send_data).with({ type: 'typing', id: 42, channel: 'channel' }.to_json) 12 | client.typing(channel: 'channel') 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/slack/real_time/event_handlers/event_handlers_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | it 'is not fatal' do 7 | event = Slack::RealTime::Event.new( 8 | 'type' => 'pref_change', 9 | 'name' => 'push_sound', 10 | 'value' => 'updated.mp3' 11 | ) 12 | expect(client.self).to receive(:prefs) { fail ArgumentError } 13 | expect { client.send(:dispatch, event) }.to_not raise_error 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /bin/commands/team_profile.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'TeamProfile methods.' 4 | command 'team_profile' do |g| 5 | g.desc 'This method is used to get the profile field definitions for this team.' 6 | g.long_desc %( This method is used to get the profile field definitions for this team. ) 7 | g.command 'get' do |c| 8 | c.flag 'visibility', desc: 'Filter by visibility.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.team_profile_get(options)) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/slack/web/api/templates/endpoints.erb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | <% files.each do |f| %> 4 | require 'slack/web/api/endpoints/<%= f %>' 5 | <% end %> 6 | 7 | module Slack 8 | module Web 9 | module Api 10 | module Endpoints 11 | include Slack::Web::Api::Mixins::Channels 12 | include Slack::Web::Api::Mixins::Users 13 | include Slack::Web::Api::Mixins::Groups 14 | 15 | <% files.each do |f| %> 16 | include <%= f.camelize %> 17 | <% end %> 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/users.search.json: -------------------------------------------------------------------------------- 1 | { 2 | "mixin": true, 3 | "group": "users", 4 | "name": "users.seaerch", 5 | "desc": "This method searches for users.", 6 | "args": { 7 | "user": { 8 | "required": true, 9 | "example": "bob", 10 | "desc": "User to search for.", 11 | "type": "user" 12 | } 13 | }, 14 | "errors": { 15 | "not_authed": "No authentication token provided.", 16 | "invalid_auth": "Invalid authentication token.", 17 | "account_inactive": "Authentication token is for a deleted user or team." 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /spec/slack/real_time/api/message_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | describe '#message' do 7 | before do 8 | allow(client).to receive(:next_id).and_return(42) 9 | end 10 | it 'sends message' do 11 | expect(socket).to receive(:send_data).with({ type: 'message', id: 42, text: 'hello world', channel: 'channel' }.to_json) 12 | client.message(text: 'hello world', channel: 'channel') 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/slack/real_time/api/ping.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Api 4 | module Ping 5 | # 6 | # Clients should try to quickly detect disconnections, even in idle periods, so that users can easily tell the 7 | # difference between being disconnected and everyone being quiet. Not all web browsers support the WebSocket 8 | # ping spec, so the RTM protocol also supports ping/pong messages. 9 | # 10 | def ping(options = {}) 11 | send_json({ type: 'ping', id: next_id }.merge(options)) 12 | end 13 | end 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/emoji.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Emoji 8 | # 9 | # This method lists the custom emoji for a team. 10 | # 11 | # @see https://api.slack.com/methods/emoji.list 12 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/emoji/emoji.list.json 13 | def emoji_list(options = {}) 14 | post('emoji.list', options) 15 | end 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/reactions_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Reactions do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'reactions_add' do 8 | it 'requires name' do 9 | expect { client.reactions_add }.to raise_error ArgumentError, /Required arguments :name missing/ 10 | end 11 | end 12 | context 'reactions_remove' do 13 | it 'requires name' do 14 | expect { client.reactions_remove }.to raise_error ArgumentError, /Required arguments :name missing/ 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/users.id.json: -------------------------------------------------------------------------------- 1 | { 2 | "mixin": true, 3 | "group": "users", 4 | "name": "users.id", 5 | "desc": "This method returns the ID of a team user.", 6 | "args": { 7 | "user": { 8 | "required": true, 9 | "example": "#general", 10 | "desc": "User to get ID for, prefixed with @.", 11 | "type": "user" 12 | } 13 | }, 14 | "errors": { 15 | "user_not_found": "Value passed for user was invalid.", 16 | "not_authed": "No authentication token provided.", 17 | "invalid_auth": "Invalid authentication token.", 18 | "account_inactive": "Authentication token is for a deleted user or team." 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/groups.id.json: -------------------------------------------------------------------------------- 1 | { 2 | "mixin": true, 3 | "group": "groups", 4 | "name": "groups.id", 5 | "desc": "This method returns the ID of a group.", 6 | "args": { 7 | "channel": { 8 | "required": true, 9 | "example": "#general", 10 | "desc": "Group channel to get ID for, prefixed with #.", 11 | "type": "group" 12 | } 13 | }, 14 | "errors": { 15 | "channel_not_found": "Value passed for group was invalid.", 16 | "not_authed": "No authentication token provided.", 17 | "invalid_auth": "Invalid authentication token.", 18 | "account_inactive": "Authentication token is for a deleted user or team." 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /spec/slack/real_time/concurrency/it_behaves_like_a_realtime_socket.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.shared_examples_for 'a realtime socket' do 4 | let(:url) { 'wss://ms174.slack-msgs.com/websocket/xyz' } 5 | let(:logger) { ::Logger.new($stdout) } 6 | let(:socket) { described_class.new(url, ping: 42, logger: logger) } 7 | describe '#initialize' do 8 | it 'sets url' do 9 | expect(socket.url).to eq url 10 | end 11 | end 12 | describe 'api' do 13 | [:start_sync, :start_sync, :disconnect!, :connect!, :connected?, :send_data, :close].each do |m| 14 | it m do 15 | expect(socket).to respond_to(m) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | 3 | cache: bundler 4 | 5 | matrix: 6 | include: 7 | - rvm: 2.3.0 8 | script: 9 | - bundle exec danger 10 | - rvm: 2.3.0 11 | env: CONCURRENCY=celluloid-io 12 | - rvm: 2.3.0 13 | env: CONCURRENCY=faye-websocket 14 | - rvm: 2.2 15 | - rvm: 2.1 16 | - rvm: 2.0 17 | - rvm: rbx-2 18 | - rvm: jruby-19mode 19 | - rvm: ruby-head 20 | - rvm: jruby-head 21 | allow_failures: 22 | - rvm: ruby-head 23 | - rvm: jruby-head 24 | - rvm: jruby-19mode 25 | - rvm: rbx-2 26 | 27 | git: 28 | submodules: false 29 | 30 | before_install: 31 | - gem update bundler 32 | - gem update --system 33 | -------------------------------------------------------------------------------- /lib/slack/real_time/api/typing.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Api 4 | module Typing 5 | # 6 | # Send a typing indicator to indicate that the user is currently writing a message. 7 | # 8 | # @option options [channel] :channel 9 | # Channel to send message to. Can be a public channel, private group or IM channel. Can be an encoded ID, or a name. 10 | def typing(options = {}) 11 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 12 | send_json({ type: 'typing', id: next_id }.merge(options)) 13 | end 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/channels.id.json: -------------------------------------------------------------------------------- 1 | { 2 | "mixin": true, 3 | "group": "channels", 4 | "name": "channels.id", 5 | "desc": "This method returns the ID of a team channel.", 6 | "args": { 7 | "channel": { 8 | "required": true, 9 | "example": "#general", 10 | "desc": "Channel to get ID for, prefixed with #.", 11 | "type": "channel" 12 | } 13 | }, 14 | "errors": { 15 | "channel_not_found": "Value passed for channel was invalid.", 16 | "not_authed": "No authentication token provided.", 17 | "invalid_auth": "Invalid authentication token.", 18 | "account_inactive": "Authentication token is for a deleted user or team." 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/bots.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Bots 8 | # 9 | # This method returns information about a bot user. 10 | # 11 | # @option options [Object] :bot 12 | # Bot user to get info on. 13 | # @see https://api.slack.com/methods/bots.info 14 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/bots/bots.info.json 15 | def bots_info(options = {}) 16 | post('bots.info', options) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/support/real_time/concurrency/mock.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Concurrency 4 | module Mock 5 | class WebSocket 6 | end 7 | 8 | class Socket < ::Slack::RealTime::Socket 9 | def self.close 10 | end 11 | 12 | def start_async(client) 13 | reactor = Thread.new {} 14 | client.run_loop 15 | reactor 16 | end 17 | 18 | def send_data(message) 19 | driver.send(message) 20 | end 21 | 22 | protected 23 | 24 | def connect 25 | @driver = WebSocket.new(url, nil, options) 26 | end 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/team_profile.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module TeamProfile 8 | # 9 | # This method is used to get the profile field definitions for this team. 10 | # 11 | # @option options [Object] :visibility 12 | # Filter by visibility. 13 | # @see https://api.slack.com/methods/team.profile.get 14 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/team.profile/team.profile.get.json 15 | def team_profile_get(options = {}) 16 | post('team.profile.get', options) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /lib/slack/web/client.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | class Client 4 | include Faraday::Connection 5 | include Faraday::Request 6 | include Api::Endpoints 7 | 8 | attr_accessor(*Config::ATTRIBUTES) 9 | 10 | def initialize(options = {}) 11 | Slack::Web::Config::ATTRIBUTES.each do |key| 12 | send("#{key}=", options[key] || Slack::Web.config.send(key)) 13 | end 14 | @logger ||= Slack::Config.logger || Slack::Logger.default 15 | @token ||= Slack.config.token 16 | end 17 | 18 | class << self 19 | def configure 20 | block_given? ? yield(Config) : Config 21 | end 22 | 23 | def config 24 | Config 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /examples/new_ticket/new_ticket.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | 3 | Slack.configure do |config| 4 | config.token = ENV['SLACK_API_TOKEN'] 5 | fail 'Missing ENV[SLACK_API_TOKEN]!' unless config.token 6 | end 7 | 8 | client = Slack::Web::Client.new 9 | 10 | client.auth_test 11 | 12 | client.chat_postMessage( 13 | channel: '#general', 14 | as_user: true, 15 | attachments: [ 16 | { 17 | fallback: "Ticket #1943: Can't rest my password - https://groove.hq/path/to/ticket/1943", 18 | pretext: 'New ticket from Andrea Lee', 19 | title: "Ticket #1943: Can't reset my password", 20 | title_link: 'https://groove.hq/path/to/ticket/1943', 21 | text: 'Help! I tried to reset my password but nothing happened!', 22 | color: '#7CD197' 23 | } 24 | ] 25 | ) 26 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/api.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Api 8 | # 9 | # This method helps you test your calling code. 10 | # 11 | # @option options [Object] :error 12 | # Error response to return. 13 | # @option options [Object] :foo 14 | # example property to return. 15 | # @see https://api.slack.com/methods/api.test 16 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/api/api.test.json 17 | def api_test(options = {}) 18 | post('api.test', options) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /examples/hi_real_time_and_web/hi.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | 3 | Slack.configure do |config| 4 | config.token = ENV['SLACK_API_TOKEN'] 5 | fail 'Missing ENV[SLACK_API_TOKEN]!' unless config.token 6 | end 7 | 8 | client = Slack::RealTime::Client.new 9 | 10 | client.on :hello do 11 | puts "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." 12 | end 13 | 14 | client.on :message do |data| 15 | puts data 16 | case data.text 17 | when 'bot hi' then 18 | client.web_client.chat_postMessage channel: data.channel, text: "Hi <@#{data.user}>!" 19 | when /^bot/ then 20 | client.web_client.chat_postMessage channel: data.channel, text: "Sorry <@#{data.user}>, what?" 21 | end 22 | end 23 | 24 | client.start! 25 | -------------------------------------------------------------------------------- /lib/slack/real_time/stores/base.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Stores 4 | # Doesn't store anything. 5 | class Base 6 | class_attribute :events 7 | 8 | attr_accessor :users 9 | attr_accessor :bots 10 | attr_accessor :channels 11 | attr_accessor :groups 12 | attr_accessor :teams 13 | attr_accessor :ims 14 | 15 | def self 16 | nil 17 | end 18 | 19 | def team 20 | nil 21 | end 22 | 23 | def initialize(_attrs) 24 | end 25 | 26 | def self.on(event, &block) 27 | self.events ||= {} 28 | self.events[event.to_s] ||= [] 29 | self.events[event.to_s] << block 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/support/real_time/connected_client.rb: -------------------------------------------------------------------------------- 1 | RSpec.shared_context 'connected client' do |opts| 2 | let(:client) { Slack::RealTime::Client.new(opts || {}) } 3 | let(:ws) { double(Slack::RealTime::Concurrency::Mock::WebSocket) } 4 | let(:url) { 'wss://ms173.slack-msgs.com/websocket/lqcUiAvrKTP-uuid=' } 5 | let(:socket) { double(Slack::RealTime::Socket, connected?: true) } 6 | before do 7 | Slack::RealTime.configure do |config| 8 | config.concurrency = Slack::RealTime::Concurrency::Mock 9 | end 10 | allow(Slack::RealTime::Socket).to receive(:new).with(url, ping: 30, logger: Slack::Logger.default).and_return(socket) 11 | allow(socket).to receive(:start_sync) 12 | allow(socket).to receive(:connect!) 13 | allow(ws).to receive(:on) 14 | client.start! 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/custom_specs/auth_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Endpoints::Auth do 4 | let(:client) { Slack::Web::Client.new } 5 | context 'without auth', vcr: { cassette_name: 'web/auth_test_error' } do 6 | it 'fails with an exception' do 7 | expect { client.auth_test }.to raise_error Slack::Web::Api::Error, 'not_authed' 8 | end 9 | end 10 | context 'with auth', vcr: { cassette_name: 'web/auth_test_success' } do 11 | it 'succeeds' do 12 | expect { client.auth_test }.to_not raise_error 13 | end 14 | end 15 | context '429 error', vcr: { cassette_name: 'web/429_error' } do 16 | it 'fails with an exception' do 17 | expect { client.auth_test }.to raise_error Faraday::ClientError 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/pins_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Pins do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'pins_add' do 8 | it 'requires channel' do 9 | expect { client.pins_add }.to raise_error ArgumentError, /Required arguments :channel missing/ 10 | end 11 | end 12 | context 'pins_list' do 13 | it 'requires channel' do 14 | expect { client.pins_list }.to raise_error ArgumentError, /Required arguments :channel missing/ 15 | end 16 | end 17 | context 'pins_remove' do 18 | it 'requires channel' do 19 | expect { client.pins_remove }.to raise_error ArgumentError, /Required arguments :channel missing/ 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/search_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Search do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'search_all' do 8 | it 'requires query' do 9 | expect { client.search_all }.to raise_error ArgumentError, /Required arguments :query missing/ 10 | end 11 | end 12 | context 'search_files' do 13 | it 'requires query' do 14 | expect { client.search_files }.to raise_error ArgumentError, /Required arguments :query missing/ 15 | end 16 | end 17 | context 'search_messages' do 18 | it 'requires query' do 19 | expect { client.search_messages }.to raise_error ArgumentError, /Required arguments :query missing/ 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /bin/commands/rtm.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Rtm methods.' 4 | command 'rtm' do |g| 5 | g.desc 'This method starts a Real Time Messaging API session. Refer to the' 6 | g.long_desc %( This method starts a Real Time Messaging API session. Refer to the RTM API documentation for full details on how to use the RTM API. ) 7 | g.command 'start' do |c| 8 | c.flag 'simple_latest', desc: 'Return timestamp only for latest message object of each channel (improves performance).' 9 | c.flag 'no_unreads', desc: 'Skip unread counts for each channel (improves performance).' 10 | c.flag 'mpim_aware', desc: 'Returns MPIMs to the client in the API response.' 11 | c.action do |_global_options, options, _args| 12 | puts JSON.dump($client.rtm_start(options)) 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/presence.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/slack/web/api/tasks/generate.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Presence 8 | # 9 | # Manually set user presence. 10 | # 11 | # @option options [Object] :presence 12 | # Either `active` or `away`. 13 | # @see https://api.slack.com/methods/presence.set 14 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/presence.set.json 15 | def presence_set(options = {}) 16 | throw ArgumentError.new('Required arguments :presence missing') if options[:presence].nil? 17 | post('presence.set', options) 18 | end 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /bin/commands.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'commands/api' 4 | require 'commands/auth' 5 | require 'commands/bots' 6 | require 'commands/channels' 7 | require 'commands/chat' 8 | require 'commands/dnd' 9 | require 'commands/emoji' 10 | require 'commands/files_comments' 11 | require 'commands/files' 12 | require 'commands/groups' 13 | require 'commands/im' 14 | require 'commands/mpim' 15 | require 'commands/oauth' 16 | require 'commands/pins' 17 | require 'commands/reactions' 18 | require 'commands/reminders' 19 | require 'commands/rtm' 20 | require 'commands/search' 21 | require 'commands/stars' 22 | require 'commands/team' 23 | require 'commands/team_profile' 24 | require 'commands/usergroups' 25 | require 'commands/usergroups_users' 26 | require 'commands/users' 27 | require 'commands/users_profile' 28 | -------------------------------------------------------------------------------- /lib/slack/messages/formatting.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | module Slack 3 | module Messages 4 | module Formatting 5 | class << self 6 | # 7 | # Unescape a message. 8 | # @see https://api.slack.com/docs/formatting 9 | # 10 | def unescape(message) 11 | CGI.unescapeHTML(message.gsub(/[“”]/, '"') 12 | .gsub(/[‘’]/, "'") 13 | .gsub(/<(?[?@#!]?)(?
.*?)>/) do |match| 14 | sign = $~[:sign] 15 | dt = $~[:dt] 16 | rhs = dt.split('|', 2).last 17 | case sign 18 | when '@', '!' 19 | "@#{rhs}" 20 | when '#' 21 | "##{rhs}" 22 | else 23 | rhs 24 | end 25 | end) 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/slack/real_time/api/message.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Api 4 | module Message 5 | # 6 | # Sends a message to a channel. 7 | # 8 | # @option options [channel] :channel 9 | # Channel to send message to. Can be a public channel, private group or IM channel. Can be an encoded ID, or a name. 10 | # @option options [Object] :text 11 | # Text of the message to send. See below for an explanation of formatting. 12 | def message(options = {}) 13 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 14 | throw ArgumentError.new('Required arguments :text missing') if options[:text].nil? 15 | send_json({ type: 'message', id: next_id }.merge(options)) 16 | end 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/support/queue_with_timeout.rb: -------------------------------------------------------------------------------- 1 | # http://spin.atomicobject.com/2014/07/07/ruby-queue-pop-timeout/ 2 | class QueueWithTimeout 3 | def initialize 4 | @mutex = Mutex.new 5 | @queue = [] 6 | @recieved = ConditionVariable.new 7 | end 8 | 9 | def push(x) 10 | @mutex.synchronize do 11 | @queue << x 12 | @recieved.signal 13 | end 14 | end 15 | 16 | def <<(x) 17 | push(x) 18 | end 19 | 20 | def pop(non_block = false) 21 | pop_with_timeout(non_block ? 0 : nil) 22 | end 23 | 24 | def pop_with_timeout(timeout = nil) 25 | @mutex.synchronize do 26 | if @queue.empty? 27 | @recieved.wait(@mutex, timeout) if timeout != 0 28 | # if we're still empty after the timeout, raise exception 29 | fail ThreadError, 'queue empty' if @queue.empty? 30 | end 31 | @queue.shift 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/slack/web/api/patches/chat.1.text-attachments-required.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/slack/web/api/endpoints/chat.rb b/lib/slack/web/api/endpoints/chat.rb 2 | index 1f7a8d7..2ec4bed 100644 3 | --- a/lib/slack/web/api/endpoints/chat.rb 4 | +++ b/lib/slack/web/api/endpoints/chat.rb 5 | @@ -49,7 +49,7 @@ module Slack 6 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/chat/chat.postMessage.json 7 | def chat_postMessage(options = {}) 8 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 9 | - throw ArgumentError.new('Required arguments :text missing') if options[:text].nil? 10 | + throw ArgumentError.new('Required arguments :text or :attachments missing') if options[:text].nil? && options[:attachments].nil? 11 | post('chat.postMessage', options) 12 | end 13 | 14 | -------------------------------------------------------------------------------- /bin/commands/oauth.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Oauth methods.' 4 | command 'oauth' do |g| 5 | g.desc 'This method allows you to exchange a temporary OAuth code for an API access token.' 6 | g.long_desc %( This method allows you to exchange a temporary OAuth code for an API access token. This is used as part of the OAuth authentication flow. ) 7 | g.command 'access' do |c| 8 | c.flag 'client_id', desc: 'Issued when you created your application.' 9 | c.flag 'client_secret', desc: 'Issued when you created your application.' 10 | c.flag 'code', desc: 'The code param returned via the OAuth callback.' 11 | c.flag 'redirect_uri', desc: 'This must match the originally submitted URI (if one was sent).' 12 | c.action do |_global_options, options, _args| 13 | puts JSON.dump($client.oauth_access(options)) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/oauth_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Oauth do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'oauth_access' do 8 | it 'requires client_id' do 9 | expect { client.oauth_access(client_secret: '33fea0113f5b1', code: 'ccdaa72ad') }.to raise_error ArgumentError, /Required arguments :client_id missing/ 10 | end 11 | it 'requires client_secret' do 12 | expect { client.oauth_access(client_id: '4b39e9-752c4', code: 'ccdaa72ad') }.to raise_error ArgumentError, /Required arguments :client_secret missing/ 13 | end 14 | it 'requires code' do 15 | expect { client.oauth_access(client_id: '4b39e9-752c4', client_secret: '33fea0113f5b1') }.to raise_error ArgumentError, /Required arguments :code missing/ 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/usergroups_users_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::UsergroupsUsers do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'usergroups.users_list' do 8 | it 'requires usergroup' do 9 | expect { client.usergroups_users_list }.to raise_error ArgumentError, /Required arguments :usergroup missing/ 10 | end 11 | end 12 | context 'usergroups.users_update' do 13 | it 'requires usergroup' do 14 | expect { client.usergroups_users_update(users: 'U060R4BJ4,U060RNRCZ') }.to raise_error ArgumentError, /Required arguments :usergroup missing/ 15 | end 16 | it 'requires users' do 17 | expect { client.usergroups_users_update(usergroup: 'S0604QSJC') }.to raise_error ArgumentError, /Required arguments :users missing/ 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/custom_specs/users_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Endpoints::Users do 4 | let(:client) { Slack::Web::Client.new } 5 | context 'users' do 6 | it 'list', vcr: { cassette_name: 'web/users_list' } do 7 | json = client.users_list(presence: true) 8 | expect(json.ok).to be true 9 | expect(json.members.size).to eq 9 10 | expect(json.members.first.presence).to eq 'away' 11 | end 12 | it 'info', vcr: { cassette_name: 'web/users_info' } do 13 | json = client.users_info(user: '@aws') 14 | expect(json.user.name).to eq 'aws' 15 | end 16 | it 'search', vcr: { cassette_name: 'web/users_info' } do 17 | json = client.users_search(user: 'aws') 18 | expect(json.ok).to be true 19 | expect(json.members.size).to eq 1 20 | expect(json.members.first.name).to eq 'aws' 21 | end if defined?(Picky) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/users.id.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Api 4 | module Mixins 5 | module Users 6 | # 7 | # This method returns a user ID given a user name. 8 | # 9 | # @option options [user] :user 10 | # User to get ID for, prefixed with '@'. 11 | def users_id(options = {}) 12 | name = options[:user] 13 | throw ArgumentError.new('Required arguments :user missing') if name.nil? 14 | return { 'ok' => true, 'user' => { 'id' => name } } unless name[0] == '@' 15 | users_list.tap do |list| 16 | list.members.each do |user| 17 | return Slack::Messages::Message.new('ok' => true, 'user' => { 'id' => user.id }) if user.name == name[1..-1] 18 | end 19 | end 20 | fail Slack::Web::Api::Error, 'user_not_found' 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/groups.id.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Api 4 | module Mixins 5 | module Groups 6 | # 7 | # This method returns a group ID given a group name. 8 | # 9 | # @option options [channel] :channel 10 | # Group channel to get ID for, prefixed with #. 11 | def groups_id(options = {}) 12 | name = options[:channel] 13 | throw ArgumentError.new('Required arguments :channel missing') if name.nil? 14 | return { 'ok' => true, 'group' => { 'id' => name } } unless name[0] == '#' 15 | groups_list.tap do |list| 16 | list.groups.each do |group| 17 | return Slack::Messages::Message.new('ok' => true, 'group' => { 'id' => group.id }) if group.name == name[1..-1] 18 | end 19 | end 20 | fail Slack::Web::Api::Error, 'channel_not_found' 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/slack/web/api/templates/method_spec.erb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::<%= group.gsub(".", "_").camelize %> do 6 | let(:client) { Slack::Web::Client.new } 7 | <% names.each_with_index do |(name, data), index| %> 8 | <% next if data['mixin'] %> 9 | <% required_params = data['args'].select{ |k, v| v['required'] } %> 10 | <% next if required_params.none? %> 11 | context '<%= group %>_<%= name %>' do 12 | <% required_params.each do |arg_name, arg_v| %> 13 | it 'requires <%= arg_name %>' do 14 | <% params_except_required = required_params.reject{ |name, _| name == arg_name }.map{|var, opts| "#{var}: '#{opts['example']}'"}.join(', ') %> 15 | expect { client.<%= group.gsub(".", "_") %>_<%= name %><%= params_except_required.empty? ? '' : "(#{params_except_required})" %> }.to raise_error ArgumentError, /Required arguments :<%= arg_name %> missing/ 16 | end 17 | <% end %> 18 | end 19 | <% end %> 20 | end 21 | -------------------------------------------------------------------------------- /lib/slack/web/api/patches/chat.2.attachments-json.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/slack/web/api/endpoints/chat.rb b/lib/slack/web/api/endpoints/chat.rb 2 | index 1f7a8d7..89b1562 100644 3 | --- a/lib/slack/web/api/endpoints/chat.rb 4 | +++ b/lib/slack/web/api/endpoints/chat.rb 5 | @@ -50,6 +50,12 @@ module Slack 6 | def chat_postMessage(options = {}) 7 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 8 | throw ArgumentError.new('Required arguments :text or :attachments missing') if options[:text].nil? && options[:attachments].nil? 9 | + # attachments must be passed as an encoded JSON string 10 | + if options.key?(:attachments) 11 | + attachments = options[:attachments] 12 | + attachments = JSON.dump(attachments) unless attachments.is_a?(String) 13 | + options = options.merge(attachments: attachments) 14 | + end 15 | post('chat.postMessage', options) 16 | end 17 | 18 | -------------------------------------------------------------------------------- /lib/slack/web/config.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Config 4 | extend self 5 | 6 | ATTRIBUTES = [ 7 | :proxy, 8 | :user_agent, 9 | :ca_path, 10 | :ca_file, 11 | :logger, 12 | :endpoint, 13 | :token 14 | ].freeze 15 | 16 | attr_accessor(*Config::ATTRIBUTES) 17 | 18 | def reset 19 | self.endpoint = 'https://slack.com/api/' 20 | self.user_agent = "Slack Ruby Client/#{Slack::VERSION}" 21 | self.ca_path = `openssl version -a | grep OPENSSLDIR | awk '{print $2}'|sed -e 's/\"//g'` 22 | self.ca_file = "#{ca_path}/ca-certificates.crt" 23 | self.token = nil 24 | self.proxy = nil 25 | self.logger = nil 26 | end 27 | end 28 | 29 | class << self 30 | def configure 31 | block_given? ? yield(Config) : Config 32 | end 33 | 34 | def config 35 | Config 36 | end 37 | end 38 | end 39 | end 40 | 41 | Slack::Web::Config.reset 42 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/channels.id.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Api 4 | module Mixins 5 | module Channels 6 | # 7 | # This method returns a channel ID given a channel name. 8 | # 9 | # @option options [channel] :channel 10 | # Channel to get ID for, prefixed with #. 11 | def channels_id(options = {}) 12 | name = options[:channel] 13 | throw ArgumentError.new('Required arguments :channel missing') if name.nil? 14 | return { 'ok' => true, 'channel' => { 'id' => name } } unless name[0] == '#' 15 | channels_list.tap do |list| 16 | list.channels.each do |channel| 17 | return Slack::Messages::Message.new('ok' => true, 'channel' => { 'id' => channel.id }) if channel.name == name[1..-1] 18 | end 19 | end 20 | fail Slack::Web::Api::Error, 'channel_not_found' 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/slack/real_time/concurrency/celluloid_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require_relative './it_behaves_like_a_realtime_socket' 3 | 4 | begin 5 | RSpec.describe Slack::RealTime::Concurrency::Celluloid::Socket do 6 | it_behaves_like 'a realtime socket' 7 | context 'with url' do 8 | let(:url) { 'wss://echo.websocket.org/websocket/xyz' } 9 | let(:logger) { ::Logger.new(STDOUT) } 10 | subject(:socket) { described_class.new(url, ping: 42, logger: logger) } 11 | let(:driver) { WebSocket::Driver::Client } 12 | let(:ws) { double(driver) } 13 | 14 | describe '#connect!' do 15 | pending 'connects' 16 | pending 'pings every 30s' 17 | end 18 | 19 | describe '#disconnect!' do 20 | it 'closes and nils the websocket' do 21 | socket.instance_variable_set('@driver', ws) 22 | expect(ws).to receive(:close) 23 | socket.disconnect! 24 | end 25 | end 26 | 27 | pending 'send_data' 28 | end 29 | end 30 | rescue LoadError 31 | end 32 | -------------------------------------------------------------------------------- /examples/hi_real_time/hi.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | 3 | Slack.configure do |config| 4 | config.token = ENV['SLACK_API_TOKEN'] 5 | config.logger = Logger.new(STDOUT) 6 | config.logger.level = Logger::INFO 7 | fail 'Missing ENV[SLACK_API_TOKEN]!' unless config.token 8 | end 9 | 10 | client = Slack::RealTime::Client.new 11 | 12 | client.on :hello do 13 | puts "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." 14 | end 15 | 16 | client.on :message do |data| 17 | puts data 18 | 19 | client.typing channel: data.channel 20 | 21 | case data.text 22 | when 'bot hi' then 23 | client.message channel: data.channel, text: "Hi <@#{data.user}>!" 24 | when /^bot/ then 25 | client.message channel: data.channel, text: "Sorry <@#{data.user}>, what?" 26 | end 27 | end 28 | 29 | client.on :close do |_data| 30 | puts 'Connection closing, exiting.' 31 | end 32 | 33 | client.on :closed do |_data| 34 | puts 'Connection has been disconnected.' 35 | end 36 | 37 | client.start! 38 | -------------------------------------------------------------------------------- /examples/hi_real_time_async_celluloid/hi.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | 3 | fail 'Missing ENV[SLACK_API_TOKENS]!' unless ENV.key?('SLACK_API_TOKENS') 4 | 5 | $stdout.sync = true 6 | logger = Logger.new($stdout) 7 | logger.level = Logger::DEBUG 8 | 9 | ENV['SLACK_API_TOKENS'].split.each do |token| 10 | logger.info "Starting #{token[0..12]} ..." 11 | 12 | client = Slack::RealTime::Client.new(token: token) 13 | 14 | client.on :hello do 15 | logger.info "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." 16 | end 17 | 18 | client.on :message do |data| 19 | logger.info data 20 | 21 | client.typing channel: data.channel 22 | 23 | case data.text 24 | when 'bot hi' then 25 | client.message channel: data.channel, text: "Hi <@#{data.user}>!" 26 | when /^bot/ then 27 | client.message channel: data.channel, text: "Sorry <@#{data.user}>, what?" 28 | end 29 | end 30 | 31 | client.start_async 32 | end 33 | 34 | loop do 35 | Thread.pass 36 | end 37 | -------------------------------------------------------------------------------- /examples/hi_real_time_async_eventmachine/hi.rb: -------------------------------------------------------------------------------- 1 | require 'slack-ruby-client' 2 | 3 | fail 'Missing ENV[SLACK_API_TOKENS]!' unless ENV.key?('SLACK_API_TOKENS') 4 | 5 | $stdout.sync = true 6 | logger = Logger.new($stdout) 7 | logger.level = Logger::DEBUG 8 | 9 | ENV['SLACK_API_TOKENS'].split.each do |token| 10 | logger.info "Starting #{token[0..12]} ..." 11 | 12 | client = Slack::RealTime::Client.new(token: token) 13 | 14 | client.on :hello do 15 | logger.info "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." 16 | end 17 | 18 | client.on :message do |data| 19 | logger.info data 20 | 21 | client.typing channel: data.channel 22 | 23 | case data.text 24 | when 'bot hi' then 25 | client.message channel: data.channel, text: "Hi <@#{data.user}>!" 26 | when /^bot/ then 27 | client.message channel: data.channel, text: "Sorry <@#{data.user}>, what?" 28 | end 29 | end 30 | 31 | client.start_async 32 | end 33 | 34 | loop do 35 | Thread.pass 36 | end 37 | -------------------------------------------------------------------------------- /lib/slack/web/api/schema/method.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "required": [ 4 | "desc", 5 | "args", 6 | "errors" 7 | ], 8 | "properties": { 9 | "desc": { 10 | "type": "string" 11 | }, 12 | "args": { 13 | "type": "object", 14 | "default": {}, 15 | "patternProperties": { 16 | "^.+$": { 17 | "properties": { 18 | "required": { 19 | "type": "bool", 20 | "default": false 21 | }, 22 | "example": { 23 | "type": "any", 24 | "required": false, 25 | "default": "" 26 | }, 27 | "type": { 28 | "type": "any", 29 | "required": false, 30 | "default": "Object" 31 | }, 32 | "desc": { 33 | "type": "string", 34 | "required": true 35 | } 36 | } 37 | } 38 | } 39 | }, 40 | "errors": { 41 | "type": "object", 42 | "default": {} 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/usergroups_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Usergroups do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'usergroups_create' do 8 | it 'requires name' do 9 | expect { client.usergroups_create }.to raise_error ArgumentError, /Required arguments :name missing/ 10 | end 11 | end 12 | context 'usergroups_disable' do 13 | it 'requires usergroup' do 14 | expect { client.usergroups_disable }.to raise_error ArgumentError, /Required arguments :usergroup missing/ 15 | end 16 | end 17 | context 'usergroups_enable' do 18 | it 'requires usergroup' do 19 | expect { client.usergroups_enable }.to raise_error ArgumentError, /Required arguments :usergroup missing/ 20 | end 21 | end 22 | context 'usergroups_update' do 23 | it 'requires usergroup' do 24 | expect { client.usergroups_update }.to raise_error ArgumentError, /Required arguments :usergroup missing/ 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /bin/commands/auth.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Auth methods.' 4 | command 'auth' do |g| 5 | g.desc 'This method revokes an access token. Use it when you no longer need a token. For example, with a Sign In With Slack app, call this to log a user out.' 6 | g.long_desc %( This method revokes an access token. Use it when you no longer need a token. For example, with a Sign In With Slack app, call this to log a user out. ) 7 | g.command 'revoke' do |c| 8 | c.flag 'test', desc: 'Setting this parameter to 1 triggers a testing mode where the specified token will not actually be revoked.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.auth_revoke(options)) 11 | end 12 | end 13 | 14 | g.desc 'This method checks authentication and tells you who you are.' 15 | g.long_desc %( This method checks authentication and tells you who you are. ) 16 | g.command 'test' do |c| 17 | c.action do |_global_options, options, _args| 18 | puts JSON.dump($client.auth_test(options)) 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/slack/web/faraday/request.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Faraday 4 | module Request 5 | def get(path, options = {}) 6 | request(:get, path, options) 7 | end 8 | 9 | def post(path, options = {}) 10 | request(:post, path, options) 11 | end 12 | 13 | def put(path, options = {}) 14 | request(:put, path, options) 15 | end 16 | 17 | def delete(path, options = {}) 18 | request(:delete, path, options) 19 | end 20 | 21 | private 22 | 23 | def request(method, path, options) 24 | options = options.merge(token: token) 25 | response = connection.send(method) do |request| 26 | case method 27 | when :get, :delete 28 | request.url(path, options) 29 | when :post, :put 30 | request.path = path 31 | request.body = options unless options.empty? 32 | end 33 | end 34 | response.body 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/rtm.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Rtm 8 | # 9 | # This method starts a Real Time Messaging API session. Refer to the 10 | # RTM API documentation for full details on how to use the RTM API. 11 | # 12 | # @option options [Object] :simple_latest 13 | # Return timestamp only for latest message object of each channel (improves performance). 14 | # @option options [Object] :no_unreads 15 | # Skip unread counts for each channel (improves performance). 16 | # @option options [Object] :mpim_aware 17 | # Returns MPIMs to the client in the API response. 18 | # @see https://api.slack.com/methods/rtm.start 19 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/rtm/rtm.start.json 20 | def rtm_start(options = {}) 21 | post('rtm.start', options) 22 | end 23 | end 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/im_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Im do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'im_close' do 8 | it 'requires channel' do 9 | expect { client.im_close }.to raise_error ArgumentError, /Required arguments :channel missing/ 10 | end 11 | end 12 | context 'im_history' do 13 | it 'requires channel' do 14 | expect { client.im_history }.to raise_error ArgumentError, /Required arguments :channel missing/ 15 | end 16 | end 17 | context 'im_mark' do 18 | it 'requires channel' do 19 | expect { client.im_mark(ts: '1234567890.123456') }.to raise_error ArgumentError, /Required arguments :channel missing/ 20 | end 21 | it 'requires ts' do 22 | expect { client.im_mark(channel: 'D1234567890') }.to raise_error ArgumentError, /Required arguments :ts missing/ 23 | end 24 | end 25 | context 'im_open' do 26 | it 'requires user' do 27 | expect { client.im_open }.to raise_error ArgumentError, /Required arguments :user missing/ 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/slack/web/faraday/connection.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Faraday 4 | module Connection 5 | private 6 | 7 | def connection 8 | options = { 9 | headers: { 'Accept' => 'application/json; charset=utf-8' } 10 | } 11 | 12 | options[:headers]['User-Agent'] = user_agent if user_agent 13 | options[:proxy] = proxy if proxy 14 | options[:ssl] = { ca_path: ca_path, ca_file: ca_file } 15 | 16 | ::Faraday::Connection.new(endpoint, options) do |connection| 17 | connection.use ::Faraday::Request::Multipart 18 | connection.use ::Faraday::Request::UrlEncoded 19 | connection.use ::Slack::Web::Faraday::Response::RaiseError 20 | connection.use ::FaradayMiddleware::Mashify, mash_class: Slack::Messages::Message 21 | connection.use ::FaradayMiddleware::ParseJson 22 | connection.use ::Faraday::Response::RaiseError 23 | connection.response :logger, logger if logger 24 | connection.adapter ::Faraday.default_adapter 25 | end 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015-2016 Daniel Doubrovkine, Artsy and Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/mpim_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Mpim do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'mpim_close' do 8 | it 'requires channel' do 9 | expect { client.mpim_close }.to raise_error ArgumentError, /Required arguments :channel missing/ 10 | end 11 | end 12 | context 'mpim_history' do 13 | it 'requires channel' do 14 | expect { client.mpim_history }.to raise_error ArgumentError, /Required arguments :channel missing/ 15 | end 16 | end 17 | context 'mpim_mark' do 18 | it 'requires channel' do 19 | expect { client.mpim_mark(ts: '1234567890.123456') }.to raise_error ArgumentError, /Required arguments :channel missing/ 20 | end 21 | it 'requires ts' do 22 | expect { client.mpim_mark(channel: 'G1234567890') }.to raise_error ArgumentError, /Required arguments :ts missing/ 23 | end 24 | end 25 | context 'mpim_open' do 26 | it 'requires users' do 27 | expect { client.mpim_open }.to raise_error ArgumentError, /Required arguments :users missing/ 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/slack/web/api/templates/command.erb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | <% desc = group['desc'] || "#{group['name'].gsub(".", "_").camelize} methods." %> 4 | <% if desc.include?("'") %> 5 | desc "<%= desc %>" 6 | <% else %> 7 | desc '<%= desc %>' 8 | <% end %> 9 | command '<%= group['name'].gsub(".", "_") %>' do |g| 10 | <% names.each_with_index do |(name, data), index| %> 11 | <% if index > 0 %> 12 | 13 | <% end %> 14 | <% short_desc = data["desc"].split("\n").first %> 15 | <% if short_desc.include?("'") %> 16 | g.desc "<%= short_desc %>" 17 | <% else %> 18 | g.desc '<%= short_desc %>' 19 | <% end %> 20 | g.long_desc %( <%= data["desc"].split("\n").join(" ") %> ) 21 | g.command '<%= name %>' do |c| 22 | <% data["args"].each do |arg_name, arg_v| %> 23 | <% if arg_v["desc"].include?("'") %> 24 | c.flag '<%= arg_name %>', desc: "<%= arg_v["desc"] %>" 25 | <% else %> 26 | c.flag '<%= arg_name %>', desc: '<%= arg_v["desc"] %>' 27 | <% end %> 28 | <% end %> 29 | c.action do |_global_options, options, _args| 30 | puts JSON.dump($client.<%=group['name'].gsub(".", "_") %>_<%= name %>(options)) 31 | end 32 | end 33 | <% end %> 34 | end 35 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/files_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Files do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'files_delete' do 8 | it 'requires file' do 9 | expect { client.files_delete }.to raise_error ArgumentError, /Required arguments :file missing/ 10 | end 11 | end 12 | context 'files_info' do 13 | it 'requires file' do 14 | expect { client.files_info }.to raise_error ArgumentError, /Required arguments :file missing/ 15 | end 16 | end 17 | context 'files_revokePublicURL' do 18 | it 'requires file' do 19 | expect { client.files_revokePublicURL }.to raise_error ArgumentError, /Required arguments :file missing/ 20 | end 21 | end 22 | context 'files_sharedPublicURL' do 23 | it 'requires file' do 24 | expect { client.files_sharedPublicURL }.to raise_error ArgumentError, /Required arguments :file missing/ 25 | end 26 | end 27 | context 'files_upload' do 28 | it 'requires filename' do 29 | expect { client.files_upload }.to raise_error ArgumentError, /Required arguments :filename missing/ 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/slack-ruby-client.rb: -------------------------------------------------------------------------------- 1 | require 'slack/version' 2 | require 'slack/logger' 3 | require 'slack/config' 4 | 5 | # Messages 6 | require 'hashie' 7 | require 'slack/messages/message' 8 | require 'slack/messages/formatting' 9 | 10 | # Web API 11 | require 'faraday' 12 | require 'faraday_middleware' 13 | require 'json' 14 | require 'logger' 15 | begin 16 | require 'picky' 17 | rescue LoadError 18 | # ignore, only used in users_search 19 | end 20 | require 'slack/web/config' 21 | require 'slack/web/api/error' 22 | require 'slack/web/faraday/response/raise_error' 23 | require 'slack/web/faraday/connection' 24 | require 'slack/web/faraday/request' 25 | require 'slack/web/api/mixins' 26 | require 'slack/web/api/endpoints' 27 | require 'slack/web/client' 28 | 29 | # RealTime API 30 | require 'active_support' 31 | require 'active_support/core_ext' 32 | require 'slack/real_time/concurrency' 33 | require 'slack/real_time/socket' 34 | require 'slack/real_time/api/message_id' 35 | require 'slack/real_time/api/ping' 36 | require 'slack/real_time/api/message' 37 | require 'slack/real_time/api/typing' 38 | require 'slack/real_time/models' 39 | require 'slack/real_time/stores' 40 | require 'slack/real_time/config' 41 | require 'slack/real_time/client' 42 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/reminders_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::Reminders do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'reminders_add' do 8 | it 'requires text' do 9 | expect { client.reminders_add(time: '1602288000') }.to raise_error ArgumentError, /Required arguments :text missing/ 10 | end 11 | it 'requires time' do 12 | expect { client.reminders_add(text: 'eat a banana') }.to raise_error ArgumentError, /Required arguments :time missing/ 13 | end 14 | end 15 | context 'reminders_complete' do 16 | it 'requires reminder' do 17 | expect { client.reminders_complete }.to raise_error ArgumentError, /Required arguments :reminder missing/ 18 | end 19 | end 20 | context 'reminders_delete' do 21 | it 'requires reminder' do 22 | expect { client.reminders_delete }.to raise_error ArgumentError, /Required arguments :reminder missing/ 23 | end 24 | end 25 | context 'reminders_info' do 26 | it 'requires reminder' do 27 | expect { client.reminders_info }.to raise_error ArgumentError, /Required arguments :reminder missing/ 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/auth.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Auth 8 | # 9 | # This method revokes an access token. Use it when you no longer need a token. For example, with a Sign In With Slack app, call this to log a user out. 10 | # 11 | # @option options [Object] :test 12 | # Setting this parameter to 1 triggers a testing mode where the specified token will not actually be revoked. 13 | # @see https://api.slack.com/methods/auth.revoke 14 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/auth/auth.revoke.json 15 | def auth_revoke(options = {}) 16 | post('auth.revoke', options) 17 | end 18 | 19 | # 20 | # This method checks authentication and tells you who you are. 21 | # 22 | # @see https://api.slack.com/methods/auth.test 23 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/auth/auth.test.json 24 | def auth_test(options = {}) 25 | post('auth.test', options) 26 | end 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /spec/slack/web/api/mixins/groups_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Mixins::Groups do 4 | let(:klass) do 5 | Class.new do 6 | include Slack::Web::Api::Mixins::Groups 7 | end 8 | end 9 | subject do 10 | klass.new 11 | end 12 | before do 13 | allow(subject).to receive(:groups_list).and_return(Slack::Messages::Message.new( 14 | 'groups' => [{ 15 | 'id' => 'CDEADBEEF', 16 | 'name' => 'general' 17 | }] 18 | )) 19 | end 20 | context '#groups_id' do 21 | it 'leaves groups specified by ID alone' do 22 | expect(subject.groups_id(channel: 'C123456')).to eq('ok' => true, 'group' => { 'id' => 'C123456' }) 23 | end 24 | it 'translates a channel that starts with a #' do 25 | expect(subject.groups_id(channel: '#general')).to eq('ok' => true, 'group' => { 'id' => 'CDEADBEEF' }) 26 | end 27 | it 'fails with an exception' do 28 | expect { subject.groups_id(channel: '#invalid') }.to raise_error Slack::Web::Api::Error, 'channel_not_found' 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /slack-ruby-client.gemspec: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.push File.expand_path('../lib', __FILE__) 2 | require 'slack/version' 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'slack-ruby-client' 6 | s.bindir = 'bin' 7 | s.executables << 'slack' 8 | s.version = Slack::VERSION 9 | s.authors = ['Daniel Doubrovkine'] 10 | s.email = 'dblock@dblock.org' 11 | s.platform = Gem::Platform::RUBY 12 | s.required_rubygems_version = '>= 1.3.6' 13 | s.files = `git ls-files`.split("\n") 14 | s.test_files = `git ls-files -- spec/*`.split("\n") 15 | s.require_paths = ['lib'] 16 | s.homepage = 'http://github.com/slack-ruby/slack-ruby-client' 17 | s.licenses = ['MIT'] 18 | s.summary = 'Slack Web and RealTime API client.' 19 | s.add_dependency 'activesupport' 20 | s.add_dependency 'faraday' 21 | s.add_dependency 'faraday_middleware' 22 | s.add_dependency 'json' 23 | s.add_dependency 'websocket-driver' 24 | s.add_dependency 'gli' 25 | s.add_dependency 'hashie' 26 | s.add_development_dependency 'erubis' 27 | s.add_development_dependency 'json-schema' 28 | s.add_development_dependency 'rake', '~> 10' 29 | s.add_development_dependency 'rspec' 30 | s.add_development_dependency 'vcr' 31 | s.add_development_dependency 'webmock' 32 | s.add_development_dependency 'rubocop', '0.35.0' 33 | end 34 | -------------------------------------------------------------------------------- /spec/slack/web/api/mixins/channels_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Mixins::Channels do 4 | let(:klass) do 5 | Class.new do 6 | include Slack::Web::Api::Mixins::Channels 7 | end 8 | end 9 | subject do 10 | klass.new 11 | end 12 | before do 13 | allow(subject).to receive(:channels_list).and_return(Slack::Messages::Message.new( 14 | 'channels' => [{ 15 | 'id' => 'CDEADBEEF', 16 | 'name' => 'general' 17 | }] 18 | )) 19 | end 20 | context '#channels_id' do 21 | it 'leaves channels specified by ID alone' do 22 | expect(subject.channels_id(channel: 'C123456')).to eq('ok' => true, 'channel' => { 'id' => 'C123456' }) 23 | end 24 | it 'translates a channel that starts with a #' do 25 | expect(subject.channels_id(channel: '#general')).to eq('ok' => true, 'channel' => { 'id' => 'CDEADBEEF' }) 26 | end 27 | it 'fails with an exception' do 28 | expect { subject.channels_id(channel: '#invalid') }.to raise_error Slack::Web::Api::Error, 'channel_not_found' 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/slack/web/api/patches/chat.3.update-attachments-support.patch: -------------------------------------------------------------------------------- 1 | diff --git a/lib/slack/web/api/endpoints/chat.rb b/lib/slack/web/api/endpoints/chat.rb 2 | index 0db7e67..1c3b2ee 100644 3 | --- a/lib/slack/web/api/endpoints/chat.rb 4 | +++ b/lib/slack/web/api/endpoints/chat.rb 5 | @@ -82,8 +82,14 @@ module Slack 6 | def chat_update(options = {}) 7 | throw ArgumentError.new('Required arguments :ts missing') if options[:ts].nil? 8 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 9 | - throw ArgumentError.new('Required arguments :text missing') if options[:text].nil? 10 | + throw ArgumentError.new('Required arguments :text or :attachments missing') if options[:text].nil? && options[:attachments].nil? 11 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 12 | + # attachments must be passed as an encoded JSON string 13 | + if options.key?(:attachments) 14 | + attachments = options[:attachments] 15 | + attachments = JSON.dump(attachments) unless attachments.is_a?(String) 16 | + options = options.merge(attachments: attachments) 17 | + end 18 | post('chat.update', options) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/fixtures/slack/web/auth_test_error.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: https://slack.com/api/auth.test 6 | body: 7 | encoding: UTF-8 8 | string: token= 9 | headers: 10 | Accept: 11 | - application/json; charset=utf-8 12 | User-Agent: 13 | - Slack Ruby Client 0.1.0 14 | Content-Type: 15 | - application/x-www-form-urlencoded 16 | Accept-Encoding: 17 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 18 | response: 19 | status: 20 | code: 200 21 | message: OK 22 | headers: 23 | Access-Control-Allow-Origin: 24 | - "*" 25 | Content-Type: 26 | - application/json; charset=utf-8 27 | Date: 28 | - Sat, 25 Jul 2015 14:42:07 GMT 29 | Server: 30 | - Apache 31 | Strict-Transport-Security: 32 | - max-age=31536000; includeSubDomains; preload 33 | Vary: 34 | - Accept-Encoding 35 | X-Content-Type-Options: 36 | - nosniff 37 | X-Xss-Protection: 38 | - '0' 39 | Content-Length: 40 | - '53' 41 | Connection: 42 | - keep-alive 43 | body: 44 | encoding: UTF-8 45 | string: '{"ok":false,"error":"not_authed"}' 46 | http_version: 47 | recorded_at: Sat, 25 Jul 2015 14:42:08 GMT 48 | recorded_with: VCR 2.9.3 49 | -------------------------------------------------------------------------------- /bin/commands/users_profile.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'UsersProfile methods.' 4 | command 'users_profile' do |g| 5 | g.desc 'This method is used to get the profile information for a user.' 6 | g.long_desc %( This method is used to get the profile information for a user. ) 7 | g.command 'get' do |c| 8 | c.flag 'user', desc: 'User to retrieve profile info for.' 9 | c.flag 'include_labels', desc: 'Include labels for each ID in custom profile fields.' 10 | c.action do |_global_options, options, _args| 11 | puts JSON.dump($client.users_profile_get(options)) 12 | end 13 | end 14 | 15 | g.desc 'This method is used to set the profile information for a user.' 16 | g.long_desc %( This method is used to set the profile information for a user. ) 17 | g.command 'set' do |c| 18 | c.flag 'user', desc: 'ID of user to change. This argument may only be specified by team admins.' 19 | c.flag 'profile', desc: 'Collection of key:value pairs presented as a URL-encoded JSON hash.' 20 | c.flag 'name', desc: 'Name of a single key to set. Usable only if profile is not passed.' 21 | c.flag 'value', desc: 'Value to set a single key to. Usable only if profile is not passed.' 22 | c.action do |_global_options, options, _args| 23 | puts JSON.dump($client.users_profile_set(options)) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /spec/slack/real_time/event_handlers/bot_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | context 'bot' do 7 | it 'sets bot data on rtm.start' do 8 | expect(client.bots.count).to eq 16 9 | end 10 | it 'bot_added' do 11 | expect do 12 | event = Slack::RealTime::Event.new( 13 | 'type' => 'bot_added', 14 | 'bot' => { 15 | 'id' => 'B024BE7LH', 16 | 'name' => 'hugbot', 17 | 'icons' => { 18 | 'image_48' => 'https:\/\/slack.com\/path\/to\/hugbot_48.png' 19 | } 20 | }) 21 | client.send(:dispatch, event) 22 | end.to change(client.bots, :count).by(1) 23 | bot = client.bots['B024BE7LH'] 24 | expect(bot['id']).to eq 'B024BE7LH' 25 | expect(bot['name']).to eq 'hugbot' 26 | expect(bot['icons']['image_48']).to eq 'https:\/\/slack.com\/path\/to\/hugbot_48.png' 27 | end 28 | it 'bot_changed' do 29 | expect do 30 | event = Slack::RealTime::Event.new( 31 | 'type' => 'bot_changed', 32 | 'bot' => { 33 | 'id' => 'B0751JU2H', 34 | 'name' => 'hugbot' 35 | }) 36 | client.send(:dispatch, event) 37 | end.to_not change(client.bots, :count) 38 | bot = client.bots['B0751JU2H'] 39 | expect(bot['name']).to eq 'hugbot' 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /spec/slack/real_time/event_handlers/im_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | context 'im' do 7 | it 'sets im data' do 8 | expect(client.ims.count).to eq 2 9 | end 10 | it 'im_created' do 11 | expect(client.ims['CDEADBEEF']).to be nil 12 | event = Slack::RealTime::Event.new( 13 | 'type' => 'im_created', 14 | 'channel' => { 15 | 'id' => 'CDEADBEEF', 16 | 'name' => 'beef' 17 | } 18 | ) 19 | client.send(:dispatch, event) 20 | im = client.ims['CDEADBEEF'] 21 | expect(im).to_not be nil 22 | expect(im.name).to eq 'beef' 23 | end 24 | it 'im_open' do 25 | im = client.ims['D07519J57'] 26 | expect(im).to_not be_nil 27 | im.is_open = false 28 | event = Slack::RealTime::Event.new( 29 | 'type' => 'im_open', 30 | 'channel' => 'D07519J57' 31 | ) 32 | client.send(:dispatch, event) 33 | expect(im.is_open).to be true 34 | end 35 | it 'im_close' do 36 | im = client.ims['D07519J57'] 37 | expect(im).to_not be_nil 38 | expect(im.is_open).to be true 39 | event = Slack::RealTime::Event.new( 40 | 'type' => 'im_close', 41 | 'channel' => 'D07519J57' 42 | ) 43 | client.send(:dispatch, event) 44 | expect(im.is_open).to be false 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /bin/commands/usergroups_users.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'UsergroupsUsers methods.' 4 | command 'usergroups_users' do |g| 5 | g.desc 'This method returns a list of all users within a User Group.' 6 | g.long_desc %( This method returns a list of all users within a User Group. ) 7 | g.command 'list' do |c| 8 | c.flag 'usergroup', desc: 'The encoded ID of the User Group to update.' 9 | c.flag 'include_disabled', desc: 'Allow results that involve disabled User Groups.' 10 | c.action do |_global_options, options, _args| 11 | puts JSON.dump($client.usergroups_users_list(options)) 12 | end 13 | end 14 | 15 | g.desc 'This method updates the list of users that belong to a User Group. This method replaces all users in a User Group with the list of users provided in the users parameter.' 16 | g.long_desc %( This method updates the list of users that belong to a User Group. This method replaces all users in a User Group with the list of users provided in the users parameter. ) 17 | g.command 'update' do |c| 18 | c.flag 'usergroup', desc: 'The encoded ID of the User Group to update.' 19 | c.flag 'users', desc: 'A comma separated string of encoded user IDs that represent the entire list of users for the User Group.' 20 | c.flag 'include_count', desc: 'Include the number of users in the User Group.' 21 | c.action do |_global_options, options, _args| 22 | puts JSON.dump($client.usergroups_users_update(options)) 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/oauth.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Oauth 8 | # 9 | # This method allows you to exchange a temporary OAuth code for an API access token. 10 | # This is used as part of the OAuth authentication flow. 11 | # 12 | # @option options [Object] :client_id 13 | # Issued when you created your application. 14 | # @option options [Object] :client_secret 15 | # Issued when you created your application. 16 | # @option options [Object] :code 17 | # The code param returned via the OAuth callback. 18 | # @option options [Object] :redirect_uri 19 | # This must match the originally submitted URI (if one was sent). 20 | # @see https://api.slack.com/methods/oauth.access 21 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/oauth/oauth.access.json 22 | def oauth_access(options = {}) 23 | throw ArgumentError.new('Required arguments :client_id missing') if options[:client_id].nil? 24 | throw ArgumentError.new('Required arguments :client_secret missing') if options[:client_secret].nil? 25 | throw ArgumentError.new('Required arguments :code missing') if options[:code].nil? 26 | post('oauth.access', options) 27 | end 28 | end 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /spec/slack/web/api/mixins/users_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Mixins::Users do 4 | let(:klass) do 5 | Class.new do 6 | include Slack::Web::Api::Mixins::Users 7 | end 8 | end 9 | subject do 10 | klass.new 11 | end 12 | before do 13 | allow(subject).to receive(:users_list).and_return(Slack::Messages::Message.new( 14 | 'members' => [{ 15 | 'id' => 'UDEADBEEF', 16 | 'name' => 'aws', 17 | 'profile' => {} 18 | }] 19 | )) 20 | end 21 | context '#users_id' do 22 | it 'leaves users specified by ID alone' do 23 | expect(subject.users_id(user: 'U123456')).to eq('ok' => true, 'user' => { 'id' => 'U123456' }) 24 | end 25 | it 'translates a user that starts with a #' do 26 | expect(subject.users_id(user: '@aws')).to eq('ok' => true, 'user' => { 'id' => 'UDEADBEEF' }) 27 | end 28 | it 'fails with an exception' do 29 | expect { subject.users_id(user: '@foo') }.to raise_error Slack::Web::Api::Error, 'user_not_found' 30 | end 31 | end 32 | context '#users_search' do 33 | it 'finds a user' do 34 | expect(subject.users_search(user: 'aws')).to eq('ok' => true, 'members' => [{ 'id' => 'UDEADBEEF', 'name' => 'aws', 'profile' => {} }]) 35 | end 36 | end if defined?(Picky) 37 | end 38 | -------------------------------------------------------------------------------- /lib/slack/web/api/mixins/users.search.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module Web 3 | module Api 4 | module Mixins 5 | module Users 6 | Member = Struct.new :id, :name, :first_name, :last_name, :real_name, :email 7 | 8 | # 9 | # This method searches for users. 10 | # 11 | # @option options [user] :user 12 | # Free-formed text to search for. 13 | def users_search(options = {}) 14 | query = options[:user] 15 | throw ArgumentError.new('Required arguments :user missing') if query.nil? 16 | index = Picky::Index.new(:users) do 17 | category :name 18 | category :first_name 19 | category :last_name 20 | category :real_name 21 | category :email 22 | end 23 | members = users_list.members 24 | members.each_with_index do |member, id| 25 | user = Member.new( 26 | id, 27 | member.name, 28 | member.profile.first_name, 29 | member.profile.last_name, 30 | member.profile.real_name, 31 | member.profile.email 32 | ) 33 | index.add(user) 34 | end 35 | ids = Picky::Search.new(index).search(query, 5, 0, unique: true).ids 36 | results = ids.map { |id| members[id] } 37 | Slack::Messages::Message.new('ok' => true, 'members' => results) 38 | end 39 | end 40 | end 41 | end 42 | end 43 | end if defined?(Picky) 44 | -------------------------------------------------------------------------------- /bin/slack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'gli' 4 | require 'slack-ruby-client' 5 | 6 | include GLI::App 7 | 8 | program_desc 'Slack client.' 9 | 10 | default_command :help 11 | 12 | switch [:d, :debug], desc: 'Enable debug-level logging.', default_value: false 13 | flag [:t, 'slack-api-token'], desc: 'Slack API token.', default_value: ENV['SLACK_API_TOKEN'] 14 | flag ['vcr-cassette-name'], desc: 'Offline VCR cassette.' 15 | 16 | pre do |global_options, _command, options, _args| 17 | # global Slack configuration 18 | Slack.config.token = global_options['slack-api-token'] 19 | help_now! 'Set Slack API token via --slack-api-token or SLACK_API_TOKEN.' unless Slack.config.token && !Slack.config.token.empty? 20 | 21 | if global_options['debug'] 22 | require 'logger' 23 | logger = Logger.new(STDOUT) 24 | logger.level = Logger::DEBUG 25 | Slack::Web::Client.config.logger = logger 26 | end 27 | 28 | $client = Slack::Web::Client.new 29 | 30 | # Offline VCR cassette 31 | if global_options['vcr-cassette-name'] 32 | require 'webmock' 33 | WebMock.enable! 34 | require 'vcr' 35 | VCR.configure do |config| 36 | config.cassette_library_dir = 'spec/fixtures/slack' 37 | config.hook_into :webmock 38 | config.default_cassette_options = { record: :new_episodes } 39 | end 40 | VCR.insert_cassette global_options['vcr-cassette-name'] 41 | end 42 | 43 | # remove any nil values from options 44 | options.select! { |_k, v| v } 45 | 46 | true 47 | end 48 | 49 | $LOAD_PATH.push File.expand_path('..', __FILE__) 50 | require 'commands' 51 | 52 | exit run(ARGV) 53 | -------------------------------------------------------------------------------- /lib/slack/real_time/config.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | module Config 4 | class NoConcurrencyError < StandardError; end 5 | 6 | extend self 7 | 8 | ATTRIBUTES = [ 9 | :token, 10 | :websocket_ping, 11 | :websocket_proxy, 12 | :concurrency, 13 | :start_options, 14 | :store_class, 15 | :logger 16 | ].freeze 17 | 18 | attr_accessor(*Config::ATTRIBUTES) 19 | 20 | def reset 21 | self.websocket_ping = 30 22 | self.websocket_proxy = nil 23 | self.token = nil 24 | self.concurrency = method(:detect_concurrency) 25 | self.start_options = {} 26 | self.store_class = Slack::RealTime::Store 27 | self.logger = nil 28 | end 29 | 30 | def concurrency 31 | (val = @concurrency).respond_to?(:call) ? val.call : val 32 | end 33 | 34 | private 35 | 36 | def detect_concurrency 37 | [:Eventmachine, :Celluloid].each do |concurrency| 38 | begin 39 | return Slack::RealTime::Concurrency.const_get(concurrency) 40 | rescue LoadError, NameError 41 | false # could not be loaded, missing dependencies 42 | end 43 | end 44 | 45 | fail NoConcurrencyError, 'Missing concurrency. Add faye-websocket or celluloid-io to your Gemfile.' 46 | end 47 | end 48 | 49 | class << self 50 | def configure 51 | block_given? ? yield(Config) : Config 52 | end 53 | 54 | def config 55 | Config 56 | end 57 | end 58 | end 59 | end 60 | 61 | Slack::RealTime::Config.reset 62 | -------------------------------------------------------------------------------- /spec/fixtures/slack/web/auth_test_success.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: https://slack.com/api/auth.test 6 | body: 7 | encoding: UTF-8 8 | string: token=token 9 | headers: 10 | Accept: 11 | - application/json; charset=utf-8 12 | User-Agent: 13 | - Slack Ruby Gem 1.1.1 14 | Content-Type: 15 | - application/x-www-form-urlencoded 16 | Accept-Encoding: 17 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 18 | response: 19 | status: 20 | code: 200 21 | message: OK 22 | headers: 23 | Access-Control-Allow-Origin: 24 | - '*' 25 | Cache-Control: 26 | - private, no-cache, no-store, must-revalidate 27 | Content-Type: 28 | - application/json; charset=utf-8 29 | Date: 30 | - Tue, 28 Apr 2015 12:55:23 GMT 31 | Expires: 32 | - Mon, 26 Jul 1997 05:00:00 GMT 33 | Pragma: 34 | - no-cache 35 | Server: 36 | - Apache 37 | Strict-Transport-Security: 38 | - max-age=31536000; includeSubDomains; preload 39 | Vary: 40 | - Accept-Encoding 41 | X-Accepted-Oauth-Scopes: 42 | - identify 43 | X-Content-Type-Options: 44 | - nosniff 45 | X-Oauth-Scopes: 46 | - identify,read,post,client 47 | X-Xss-Protection: 48 | - '0' 49 | Content-Length: 50 | - '128' 51 | Connection: 52 | - keep-alive 53 | body: 54 | encoding: UTF-8 55 | string: '{"ok":true,"url":"https:\/\/rubybot.slack.com\/","team":"team_name","user":"user_name","team_id":"TDEADBEEF","user_id":"UBAADFOOD"}' 56 | http_version: 57 | recorded_at: Tue, 28 Apr 2015 12:55:22 GMT 58 | -------------------------------------------------------------------------------- /lib/slack/real_time/concurrency/eventmachine.rb: -------------------------------------------------------------------------------- 1 | require 'faye/websocket' 2 | require 'eventmachine' 3 | 4 | module Slack 5 | module RealTime 6 | module Concurrency 7 | module Eventmachine 8 | class Client < Faye::WebSocket::Client 9 | attr_reader :logger 10 | protected :logger 11 | 12 | def initialize(url, protocols = nil, options = {}) 13 | @logger = options.delete(:logger) || Slack::RealTime::Config.logger || Slack::Config.logger 14 | super 15 | end 16 | 17 | def parse(data) 18 | logger.debug("#{self.class}##{__method__}") { data } 19 | super data 20 | end 21 | 22 | def write(data) 23 | logger.debug("#{self.class}##{__method__}") { data } 24 | super data 25 | end 26 | end 27 | 28 | class Socket < Slack::RealTime::Socket 29 | def start_async(client) 30 | thread = ensure_reactor_running 31 | 32 | client.run_loop 33 | 34 | thread 35 | end 36 | 37 | def send_data(message) 38 | logger.debug("#{self.class}##{__method__}") { message } 39 | driver.send(message) 40 | end 41 | 42 | protected 43 | 44 | # @return [Thread] 45 | def ensure_reactor_running 46 | return if EventMachine.reactor_running? 47 | 48 | reactor = Thread.new { EventMachine.run } 49 | Thread.pass until EventMachine.reactor_running? 50 | reactor 51 | end 52 | 53 | def connect 54 | @driver = Client.new(url, nil, options.merge(logger: logger)) 55 | end 56 | end 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /spec/slack/real_time/concurrency/eventmachine_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | require_relative './it_behaves_like_a_realtime_socket' 3 | 4 | begin 5 | RSpec.describe Slack::RealTime::Concurrency::Eventmachine::Socket do 6 | it_behaves_like 'a realtime socket' 7 | context 'with url' do 8 | let(:url) { 'wss://ms174.slack-msgs.com/websocket/xyz' } 9 | let(:logger) { ::Logger.new($stdout) } 10 | let(:socket) { described_class.new(url, ping: 42, logger: logger) } 11 | let(:ws) { double(Faye::WebSocket::Client) } 12 | describe '#connect!' do 13 | before do 14 | allow(ws).to receive(:on).with(:close) 15 | end 16 | it 'connects' do 17 | allow(Faye::WebSocket::Client).to receive(:new).and_return(ws) 18 | socket.connect! 19 | expect(socket.instance_variable_get('@driver')).to eq ws 20 | end 21 | it 'pings every 30s' do 22 | expect(Faye::WebSocket::Client).to receive(:new).with(url, nil, ping: 42, logger: logger).and_return(ws) 23 | socket.connect! 24 | end 25 | end 26 | describe '#disconnect!' do 27 | it 'closes and nils the websocket' do 28 | socket.instance_variable_set('@driver', ws) 29 | expect(ws).to receive(:close) 30 | socket.disconnect! 31 | end 32 | end 33 | describe 'send_data' do 34 | before do 35 | allow(Faye::WebSocket::Client).to receive(:new).and_return(ws) 36 | allow(ws).to receive(:on) 37 | socket.connect! 38 | end 39 | it 'sends data' do 40 | expect(ws).to receive(:send).with('data') 41 | socket.send_data('data') 42 | end 43 | end 44 | end 45 | end 46 | rescue LoadError 47 | end 48 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/files_comments_spec.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'spec_helper' 4 | 5 | RSpec.describe Slack::Web::Api::Endpoints::FilesComments do 6 | let(:client) { Slack::Web::Client.new } 7 | context 'files.comments_add' do 8 | it 'requires file' do 9 | expect { client.files_comments_add(comment: 'Everyone should take a moment to read this file.') }.to raise_error ArgumentError, /Required arguments :file missing/ 10 | end 11 | it 'requires comment' do 12 | expect { client.files_comments_add(file: 'F1234467890') }.to raise_error ArgumentError, /Required arguments :comment missing/ 13 | end 14 | end 15 | context 'files.comments_delete' do 16 | it 'requires file' do 17 | expect { client.files_comments_delete(id: 'Fc1234567890') }.to raise_error ArgumentError, /Required arguments :file missing/ 18 | end 19 | it 'requires id' do 20 | expect { client.files_comments_delete(file: 'F1234567890') }.to raise_error ArgumentError, /Required arguments :id missing/ 21 | end 22 | end 23 | context 'files.comments_edit' do 24 | it 'requires file' do 25 | expect { client.files_comments_edit(id: 'Fc1234567890', comment: 'Everyone should take a moment to read this file, seriously.') }.to raise_error ArgumentError, /Required arguments :file missing/ 26 | end 27 | it 'requires id' do 28 | expect { client.files_comments_edit(file: 'F1234567890', comment: 'Everyone should take a moment to read this file, seriously.') }.to raise_error ArgumentError, /Required arguments :id missing/ 29 | end 30 | it 'requires comment' do 31 | expect { client.files_comments_edit(file: 'F1234567890', id: 'Fc1234567890') }.to raise_error ArgumentError, /Required arguments :comment missing/ 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /spec/slack/messages/formatting_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require 'spec_helper' 3 | 4 | describe Slack::Messages::Formatting do 5 | subject do 6 | Slack::Messages::Formatting 7 | end 8 | context '#unescape' do 9 | it 'plain text' do 10 | expect(subject.unescape('plain text')).to eq 'plain text' 11 | end 12 | it 'decodes an HTML-encoded message' do 13 | expect(subject.unescape('Hello & <world>')).to eq 'Hello & ' 14 | end 15 | it 'unescapes a user reference' do 16 | expect(subject.unescape('Hey <@U024BE7LH|bob>, did you see my file?')).to eq 'Hey @bob, did you see my file?' 17 | end 18 | it 'unescapes a user reference without a name' do 19 | expect(subject.unescape('<@U02BEFY4U> ^^^')).to eq '@U02BEFY4U ^^^' 20 | end 21 | it 'unescapes a URL without text' do 22 | expect(subject.unescape('This message contains a URL ')).to eq 'This message contains a URL http://foo.com/' 23 | end 24 | it 'unescapes a URL with text' do 25 | expect(subject.unescape('So does this one: ')).to eq 'So does this one: www.foo.com' 26 | end 27 | it 'removes mailto' do 28 | expect(subject.unescape('')).to eq 'Bob' 29 | end 30 | it 'unlinkifies references' do 31 | expect(subject.unescape('Hello <@U123|bob>, say hi to in <#C1234|general>')).to eq 'Hello @bob, say hi to @everyone in #general' 32 | end 33 | it 'can handle a lone >' do 34 | expect(subject.unescape('Hello <@U123|bob> > file.txt')).to eq 'Hello @bob > file.txt' 35 | end 36 | it 'unescapes a double smart quote' do 37 | expect(subject.unescape('“hello”')).to eq '"hello"' 38 | end 39 | it 'unescapes a single smart quote' do 40 | expect(subject.unescape('‘hello’')).to eq "'hello'" 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /bin/commands/files_comments.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'FilesComments methods.' 4 | command 'files_comments' do |g| 5 | g.desc 'Add a comment to an existing file.' 6 | g.long_desc %( Add a comment to an existing file. ) 7 | g.command 'add' do |c| 8 | c.flag 'file', desc: 'File to add a comment to.' 9 | c.flag 'comment', desc: 'Text of the comment to add.' 10 | c.flag 'channel', desc: 'Channel id (encoded) of which location to associate with the new comment.' 11 | c.action do |_global_options, options, _args| 12 | puts JSON.dump($client.files_comments_add(options)) 13 | end 14 | end 15 | 16 | g.desc 'Delete an existing comment on a file. Only the original author of the comment or a Team Administrator may delete a file comment.' 17 | g.long_desc %( Delete an existing comment on a file. Only the original author of the comment or a Team Administrator may delete a file comment. ) 18 | g.command 'delete' do |c| 19 | c.flag 'file', desc: 'File to delete a comment from.' 20 | c.flag 'id', desc: 'The comment to delete.' 21 | c.action do |_global_options, options, _args| 22 | puts JSON.dump($client.files_comments_delete(options)) 23 | end 24 | end 25 | 26 | g.desc 'Edit an existing comment on a file. Only the user who created a comment may make edits. Teams may configure a limited time window during which file comment edits are allowed.' 27 | g.long_desc %( Edit an existing comment on a file. Only the user who created a comment may make edits. Teams may configure a limited time window during which file comment edits are allowed. ) 28 | g.command 'edit' do |c| 29 | c.flag 'file', desc: 'File containing the comment to edit.' 30 | c.flag 'id', desc: 'The comment to edit.' 31 | c.flag 'comment', desc: 'Text of the comment to edit.' 32 | c.action do |_global_options, options, _args| 33 | puts JSON.dump($client.files_comments_edit(options)) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /spec/fixtures/slack/web/groups_info.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: https://slack.com/api/groups.list 6 | body: 7 | encoding: UTF-8 8 | string: token=token 9 | response: 10 | status: 11 | code: 200 12 | message: OK 13 | headers: 14 | Content-Type: 15 | - application/json; charset=utf-8 16 | body: 17 | encoding: ASCII-8BIT 18 | string: '{"ok":true,"groups":[{"id":"G0K7EV5A7","name":"mpdm-dblock--rubybot--player1-1","is_group":true,"created":1453561861,"creator":"U04KB5WQR","is_archived":false,"is_mpim":true,"members":["U04KB5WQR","U0HLFUZLJ","U07518DTL"],"topic":{"value":"Group 19 | messaging","creator":"U04KB5WQR","last_set":1453561861},"purpose":{"value":"Group 20 | messaging with: @dblock @rubybot @player1","creator":"U04KB5WQR","last_set":1453561861}}]}' 21 | http_version: 22 | recorded_at: Sat, 23 Jan 2016 15:19:10 GMT 23 | - request: 24 | method: post 25 | uri: https://slack.com/api/groups.info 26 | body: 27 | encoding: UTF-8 28 | string: channel=G0K7EV5A7&token=token 29 | response: 30 | status: 31 | code: 200 32 | message: OK 33 | headers: 34 | Content-Type: 35 | - application/json; charset=utf-8 36 | body: 37 | encoding: ASCII-8BIT 38 | string: '{"ok":true,"group":{"id":"G0K7EV5A7","name":"mpdm-dblock--rubybot--player1-1","is_group":true,"created":1453561861,"creator":"U04KB5WQR","is_archived":false,"is_mpim":true,"is_open":false,"last_read":"0000000000.000000","latest":null,"unread_count":0,"unread_count_display":0,"members":["U04KB5WQR","U0HLFUZLJ","U07518DTL"],"topic":{"value":"Group 39 | messaging","creator":"U04KB5WQR","last_set":1453561861},"purpose":{"value":"Group 40 | messaging with: @dblock @rubybot @player1","creator":"U04KB5WQR","last_set":1453561861}}}' 41 | http_version: 42 | recorded_at: Sat, 23 Jan 2016 15:19:46 GMT 43 | recorded_with: VCR 3.0.0 44 | -------------------------------------------------------------------------------- /bin/commands/pins.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Pins methods.' 4 | command 'pins' do |g| 5 | g.desc 'This method pins an item (file, file comment, channel message, or group message) to a particular channel.' 6 | g.long_desc %( This method pins an item (file, file comment, channel message, or group message) to a particular channel. The channel argument is required and one of file, file_comment, or timestamp must also be specified. ) 7 | g.command 'add' do |c| 8 | c.flag 'channel', desc: 'Channel to pin the item in.' 9 | c.flag 'file', desc: 'File to pin.' 10 | c.flag 'file_comment', desc: 'File comment to pin.' 11 | c.flag 'timestamp', desc: 'Timestamp of the message to pin.' 12 | c.action do |_global_options, options, _args| 13 | puts JSON.dump($client.pins_add(options)) 14 | end 15 | end 16 | 17 | g.desc 'This method lists the items pinned to a channel.' 18 | g.long_desc %( This method lists the items pinned to a channel. ) 19 | g.command 'list' do |c| 20 | c.flag 'channel', desc: 'Channel to get pinned items for.' 21 | c.action do |_global_options, options, _args| 22 | puts JSON.dump($client.pins_list(options)) 23 | end 24 | end 25 | 26 | g.desc 'This method un-pins an item (file, file comment, channel message, or group message) from a channel.' 27 | g.long_desc %( This method un-pins an item (file, file comment, channel message, or group message) from a channel. The channel argument is required and one of file, file_comment, or timestamp must also be specified. ) 28 | g.command 'remove' do |c| 29 | c.flag 'channel', desc: 'Channel where the item is pinned to.' 30 | c.flag 'file', desc: 'File to un-pin.' 31 | c.flag 'file_comment', desc: 'File comment to un-pin.' 32 | c.flag 'timestamp', desc: 'Timestamp of the message to un-pin.' 33 | c.action do |_global_options, options, _args| 34 | puts JSON.dump($client.pins_remove(options)) 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/tasks/real_time.rake: -------------------------------------------------------------------------------- 1 | # largely from https://github.com/aki017/slack-ruby-gem 2 | require 'json-schema' 3 | require 'erubis' 4 | 5 | namespace :slack do 6 | namespace :real_time do 7 | namespace :api do 8 | REAL_TIME_EVENTS_MARKER = '### RealTime Events'.freeze 9 | 10 | desc 'Update API.' 11 | task update: [:git_update] do 12 | event_schema = JSON.parse(File.read('lib/slack/real_time/api/schema/event.json')) 13 | events = Dir.glob('lib/slack/web/api/slack-api-ref/events/**/*.json').each_with_object({}) do |path, result| 14 | name = File.basename(path, '.json') 15 | parsed = JSON.parse(File.read(path)) 16 | JSON::Validator.validate(event_schema, parsed, insert_defaults: true) 17 | next if %w(message hello).include?(name) 18 | result[name] = parsed 19 | end 20 | 21 | event_handler_template = Erubis::Eruby.new(File.read('lib/slack/real_time/api/templates/event_handler.erb')) 22 | Dir.glob('lib/slack/real_time/stores/**/*.rb').each do |store_file| 23 | next if File.basename(store_file) == 'base.rb' 24 | STDOUT.write "#{File.basename(store_file)}:" 25 | 26 | store_file_contents = File.read(store_file) 27 | 28 | events.each_pair do |event_name, event_data| 29 | if store_file_contents.include?("on :#{event_name} do") 30 | STDOUT.write('.') 31 | else 32 | STDOUT.write('x') 33 | rendered_event_handler = event_handler_template.result( 34 | name: event_data['name'], 35 | desc: event_data['desc'] 36 | ) 37 | 38 | store_file_contents.gsub! REAL_TIME_EVENTS_MARKER, REAL_TIME_EVENTS_MARKER + "\n\n" + rendered_event_handler.rstrip 39 | end 40 | end 41 | 42 | File.open store_file, 'w' do |f| 43 | f.write store_file_contents 44 | end 45 | 46 | puts ' done.' 47 | end 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/users_profile.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module UsersProfile 8 | # 9 | # This method is used to get the profile information for a user. 10 | # 11 | # @option options [user] :user 12 | # User to retrieve profile info for. 13 | # @option options [Object] :include_labels 14 | # Include labels for each ID in custom profile fields. 15 | # @see https://api.slack.com/methods/users.profile.get 16 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/users.profile/users.profile.get.json 17 | def users_profile_get(options = {}) 18 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 19 | post('users.profile.get', options) 20 | end 21 | 22 | # 23 | # This method is used to set the profile information for a user. 24 | # 25 | # @option options [user] :user 26 | # ID of user to change. This argument may only be specified by team admins. 27 | # @option options [Object] :profile 28 | # Collection of key:value pairs presented as a URL-encoded JSON hash. 29 | # @option options [Object] :name 30 | # Name of a single key to set. Usable only if profile is not passed. 31 | # @option options [Object] :value 32 | # Value to set a single key to. Usable only if profile is not passed. 33 | # @see https://api.slack.com/methods/users.profile.set 34 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/users.profile/users.profile.set.json 35 | def users_profile_set(options = {}) 36 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 37 | post('users.profile.set', options) 38 | end 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/slack/web/api/templates/method.erb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module <%= group.gsub(".", "_").camelize %> 8 | <% names.each_with_index do |(name, data), index| %> 9 | <% next if data['mixin'] %> 10 | <% if index > 0 %> 11 | 12 | <% end %> 13 | # 14 | <% data['desc'].split("\n").each do |line| %> 15 | # <%= line %> 16 | <% end %> 17 | # 18 | <% data['args'].each do |arg_name, arg_v| %> 19 | # @option options [<%= arg_v['type'] %>] :<%= arg_name %> 20 | <% arg_v['desc'].lines.each do |l| %> 21 | <% if l.strip.length > 0 %> 22 | # <%= l.strip %> 23 | <% else %> 24 | # 25 | <% end %> 26 | <% end %> 27 | <% end %> 28 | # @see https://api.slack.com/methods/<%= group %>.<%= name %> 29 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/<%= group %>/<%= group %>.<%= name %>.json 30 | def <%= group.gsub(".", "_") %>_<%= name %>(options = {}) 31 | <% data['args'].select{ |k, v| v['required'] }.each do |arg_name, arg_v| %> 32 | throw ArgumentError.new('Required arguments :<%= arg_name %> missing') if options[:<%= arg_name %>].nil? 33 | <% end %> 34 | <% if data['group'] == 'groups' && data['args']['channel'] && !data['args']['channel']['desc'].include?('Can be an encoded ID, or a name.') %> 35 | options = options.merge(channel: groups_id(options)['group']['id']) if options[:channel] 36 | <% elsif data['args']['channel'] && !data['args']['channel']['desc'].include?('Can be an encoded ID, or a name.') %> 37 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 38 | <% end %> 39 | <% if data['args']['user'] %> 40 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 41 | <% end %> 42 | post('<%= group %>.<%= name %>', options) 43 | end 44 | <% end %> 45 | end 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing Slack-Ruby-Client 2 | 3 | There're no hard rules about when to release slack-ruby-client. Release bug fixes frequenty, features not so frequently and breaking API changes rarely. 4 | 5 | ### Release 6 | 7 | Run tests, check that all tests succeed locally. 8 | 9 | ``` 10 | bundle install 11 | rake 12 | ``` 13 | 14 | Check that the last build succeeded in [Travis CI](https://travis-ci.org/slack-ruby/slack-ruby-client) for all supported platforms. 15 | 16 | Increment the version, modify [lib/slack/version.rb](lib/slack/version.rb). 17 | 18 | * Increment the third number if the release has bug fixes and/or very minor features, only (eg. change `0.2.1` to `0.2.2`). 19 | * Increment the second number if the release contains major features or breaking API changes (eg. change `0.2.1` to `0.3.0`). 20 | 21 | Change "Next Release" in [CHANGELOG.md](CHANGELOG.md) to the new version. 22 | 23 | ``` 24 | ### 0.2.2 (7/10/2015) 25 | ``` 26 | 27 | Remove the line with "Your contribution here.", since there will be no more contributions to this release. 28 | 29 | Remove the "Stable Release" section in README that warns users that they are reading the documentation for an unreleased version. 30 | 31 | Commit your changes. 32 | 33 | ``` 34 | git add README.md CHANGELOG.md lib/slack/version.rb 35 | git commit -m "Preparing for release, 0.2.2." 36 | git push origin master 37 | ``` 38 | 39 | Release. 40 | 41 | ``` 42 | $ rake release 43 | 44 | slack-ruby-client 0.2.2 built to pkg/slack-ruby-client-0.2.2.gem. 45 | Tagged v0.2.2. 46 | Pushed git commits and tags. 47 | Pushed slack-ruby-client 0.2.2 to rubygems.org. 48 | ``` 49 | 50 | ### Prepare for the Next Version 51 | 52 | Add the next release to [CHANGELOG.md](CHANGELOG.md). 53 | 54 | ``` 55 | Next Release 56 | ============ 57 | 58 | * Your contribution here. 59 | ``` 60 | 61 | Increment the third version number in [lib/slack/version.rb](lib/slack/version.rb). 62 | 63 | Comit your changes. 64 | 65 | ``` 66 | git add CHANGELOG.md lib/slack/version.rb 67 | git commit -m "Preparing for next development iteration, 0.2.3." 68 | git push origin master 69 | ``` 70 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | require 'slack/web/api/endpoints/api' 4 | require 'slack/web/api/endpoints/auth' 5 | require 'slack/web/api/endpoints/bots' 6 | require 'slack/web/api/endpoints/channels' 7 | require 'slack/web/api/endpoints/chat' 8 | require 'slack/web/api/endpoints/dnd' 9 | require 'slack/web/api/endpoints/emoji' 10 | require 'slack/web/api/endpoints/files_comments' 11 | require 'slack/web/api/endpoints/files' 12 | require 'slack/web/api/endpoints/groups' 13 | require 'slack/web/api/endpoints/im' 14 | require 'slack/web/api/endpoints/mpim' 15 | require 'slack/web/api/endpoints/oauth' 16 | require 'slack/web/api/endpoints/pins' 17 | require 'slack/web/api/endpoints/reactions' 18 | require 'slack/web/api/endpoints/reminders' 19 | require 'slack/web/api/endpoints/rtm' 20 | require 'slack/web/api/endpoints/search' 21 | require 'slack/web/api/endpoints/stars' 22 | require 'slack/web/api/endpoints/team' 23 | require 'slack/web/api/endpoints/team_profile' 24 | require 'slack/web/api/endpoints/usergroups' 25 | require 'slack/web/api/endpoints/usergroups_users' 26 | require 'slack/web/api/endpoints/users' 27 | require 'slack/web/api/endpoints/users_profile' 28 | 29 | module Slack 30 | module Web 31 | module Api 32 | module Endpoints 33 | include Slack::Web::Api::Mixins::Channels 34 | include Slack::Web::Api::Mixins::Users 35 | include Slack::Web::Api::Mixins::Groups 36 | 37 | include Api 38 | include Auth 39 | include Bots 40 | include Channels 41 | include Chat 42 | include Dnd 43 | include Emoji 44 | include FilesComments 45 | include Files 46 | include Groups 47 | include Im 48 | include Mpim 49 | include Oauth 50 | include Pins 51 | include Reactions 52 | include Reminders 53 | include Rtm 54 | include Search 55 | include Stars 56 | include Team 57 | include TeamProfile 58 | include Usergroups 59 | include UsergroupsUsers 60 | include Users 61 | include UsersProfile 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/usergroups_users.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module UsergroupsUsers 8 | # 9 | # This method returns a list of all users within a User Group. 10 | # 11 | # @option options [Object] :usergroup 12 | # The encoded ID of the User Group to update. 13 | # @option options [Object] :include_disabled 14 | # Allow results that involve disabled User Groups. 15 | # @see https://api.slack.com/methods/usergroups.users.list 16 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/usergroups.users/usergroups.users.list.json 17 | def usergroups_users_list(options = {}) 18 | throw ArgumentError.new('Required arguments :usergroup missing') if options[:usergroup].nil? 19 | post('usergroups.users.list', options) 20 | end 21 | 22 | # 23 | # This method updates the list of users that belong to a User Group. This method replaces all users in a User Group with the list of users provided in the users parameter. 24 | # 25 | # @option options [Object] :usergroup 26 | # The encoded ID of the User Group to update. 27 | # @option options [Object] :users 28 | # A comma separated string of encoded user IDs that represent the entire list of users for the User Group. 29 | # @option options [Object] :include_count 30 | # Include the number of users in the User Group. 31 | # @see https://api.slack.com/methods/usergroups.users.update 32 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/usergroups.users/usergroups.users.update.json 33 | def usergroups_users_update(options = {}) 34 | throw ArgumentError.new('Required arguments :usergroup missing') if options[:usergroup].nil? 35 | throw ArgumentError.new('Required arguments :users missing') if options[:users].nil? 36 | post('usergroups.users.update', options) 37 | end 38 | end 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /bin/commands/search.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc "Search your team's files and messages." 4 | command 'search' do |g| 5 | g.desc 'This method allows users and applications to search both messages and files in a single call.' 6 | g.long_desc %( This method allows users and applications to search both messages and files in a single call. ) 7 | g.command 'all' do |c| 8 | c.flag 'query', desc: 'Search query. May contains booleans, etc.' 9 | c.flag 'sort', desc: 'Return matches sorted by either score or timestamp.' 10 | c.flag 'sort_dir', desc: 'Change sort direction to ascending (asc) or descending (desc).' 11 | c.flag 'highlight', desc: 'Pass a value of 1 to enable query highlight markers (see below).' 12 | c.action do |_global_options, options, _args| 13 | puts JSON.dump($client.search_all(options)) 14 | end 15 | end 16 | 17 | g.desc 'This method returns files matching a search query.' 18 | g.long_desc %( This method returns files matching a search query. ) 19 | g.command 'files' do |c| 20 | c.flag 'query', desc: 'Search query. May contain booleans, etc.' 21 | c.flag 'sort', desc: 'Return matches sorted by either score or timestamp.' 22 | c.flag 'sort_dir', desc: 'Change sort direction to ascending (asc) or descending (desc).' 23 | c.flag 'highlight', desc: 'Pass a value of 1 to enable query highlight markers (see below).' 24 | c.action do |_global_options, options, _args| 25 | puts JSON.dump($client.search_files(options)) 26 | end 27 | end 28 | 29 | g.desc 'This method returns messages matching a search query.' 30 | g.long_desc %( This method returns messages matching a search query. ) 31 | g.command 'messages' do |c| 32 | c.flag 'query', desc: 'Search query. May contains booleans, etc.' 33 | c.flag 'sort', desc: 'Return matches sorted by either score or timestamp.' 34 | c.flag 'sort_dir', desc: 'Change sort direction to ascending (asc) or descending (desc).' 35 | c.flag 'highlight', desc: 'Pass a value of 1 to enable query highlight markers (see below).' 36 | c.action do |_global_options, options, _args| 37 | puts JSON.dump($client.search_messages(options)) 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /bin/commands/reminders.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Reminders methods.' 4 | command 'reminders' do |g| 5 | g.desc 'This method creates a reminder.' 6 | g.long_desc %( This method creates a reminder. ) 7 | g.command 'add' do |c| 8 | c.flag 'text', desc: 'The content of the reminder.' 9 | c.flag 'time', desc: 'When this reminder should happen: the Unix timestamp (up to five years from now), the number of seconds until the reminder (if within 24 hours), or a natural language description (Ex. "in 15 minutes," or "every Thursday").' 10 | c.flag 'user', desc: 'The user who will receive the reminder. If no user is specified, the reminder will go to user who created it.' 11 | c.action do |_global_options, options, _args| 12 | puts JSON.dump($client.reminders_add(options)) 13 | end 14 | end 15 | 16 | g.desc 'This method completes a reminder.' 17 | g.long_desc %( This method completes a reminder. ) 18 | g.command 'complete' do |c| 19 | c.flag 'reminder', desc: 'The ID of the reminder to be marked as complete.' 20 | c.action do |_global_options, options, _args| 21 | puts JSON.dump($client.reminders_complete(options)) 22 | end 23 | end 24 | 25 | g.desc 'This method deletes a reminder.' 26 | g.long_desc %( This method deletes a reminder. ) 27 | g.command 'delete' do |c| 28 | c.flag 'reminder', desc: 'The ID of the reminder.' 29 | c.action do |_global_options, options, _args| 30 | puts JSON.dump($client.reminders_delete(options)) 31 | end 32 | end 33 | 34 | g.desc 'This method returns information about a reminder.' 35 | g.long_desc %( This method returns information about a reminder. ) 36 | g.command 'info' do |c| 37 | c.flag 'reminder', desc: 'The ID of the reminder.' 38 | c.action do |_global_options, options, _args| 39 | puts JSON.dump($client.reminders_info(options)) 40 | end 41 | end 42 | 43 | g.desc 'This method lists all reminders created by or for a given user.' 44 | g.long_desc %( This method lists all reminders created by or for a given user. ) 45 | g.command 'list' do |c| 46 | c.action do |_global_options, options, _args| 47 | puts JSON.dump($client.reminders_list(options)) 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /bin/commands/stars.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Stars methods.' 4 | command 'stars' do |g| 5 | g.desc 'This method adds a star to an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user.' 6 | g.long_desc %( This method adds a star to an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user. One of file, file_comment, channel, or the combination of channel and timestamp must be specified. ) 7 | g.command 'add' do |c| 8 | c.flag 'file', desc: 'File to add star to.' 9 | c.flag 'file_comment', desc: 'File comment to add star to.' 10 | c.flag 'channel', desc: 'Channel to add star to, or channel where the message to add star to was posted (used with timestamp).' 11 | c.flag 'timestamp', desc: 'Timestamp of the message to add star to.' 12 | c.action do |_global_options, options, _args| 13 | puts JSON.dump($client.stars_add(options)) 14 | end 15 | end 16 | 17 | g.desc 'This method lists the items starred by the authed user.' 18 | g.long_desc %( This method lists the items starred by the authed user. ) 19 | g.command 'list' do |c| 20 | c.action do |_global_options, options, _args| 21 | puts JSON.dump($client.stars_list(options)) 22 | end 23 | end 24 | 25 | g.desc 'This method removes a star from an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user.' 26 | g.long_desc %( This method removes a star from an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user. One of file, file_comment, channel, or the combination of channel and timestamp must be specified. ) 27 | g.command 'remove' do |c| 28 | c.flag 'file', desc: 'File to remove star from.' 29 | c.flag 'file_comment', desc: 'File comment to remove star from.' 30 | c.flag 'channel', desc: 'Channel to remove star from, or channel where the message to remove star from was posted (used with timestamp).' 31 | c.flag 'timestamp', desc: 'Timestamp of the message to remove star from.' 32 | c.action do |_global_options, options, _args| 33 | puts JSON.dump($client.stars_remove(options)) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/slack/real_time/socket.rb: -------------------------------------------------------------------------------- 1 | module Slack 2 | module RealTime 3 | class Socket 4 | attr_accessor :url 5 | attr_accessor :options 6 | attr_reader :driver 7 | attr_reader :logger 8 | protected :logger 9 | 10 | def initialize(url, options = {}) 11 | @url = url 12 | @options = options 13 | @driver = nil 14 | @logger = options.delete(:logger) || Slack::RealTime::Config.logger || Slack::Config.logger 15 | end 16 | 17 | def send_data(message) 18 | logger.debug("#{self.class}##{__method__}") { message } 19 | case message 20 | when Numeric then driver.text(message.to_s) 21 | when String then driver.text(message) 22 | when Array then driver.binary(message) 23 | else false 24 | end 25 | end 26 | 27 | def connect! 28 | return if connected? 29 | 30 | connect 31 | logger.debug("#{self.class}##{__method__}") { driver.class } 32 | 33 | yield driver if block_given? 34 | end 35 | 36 | def disconnect! 37 | driver.close 38 | end 39 | 40 | def connected? 41 | !driver.nil? 42 | end 43 | 44 | def start_sync(client) 45 | thread = start_async(client) 46 | thread.join if thread 47 | rescue Interrupt 48 | thread.exit if thread 49 | end 50 | 51 | # @return [#join] 52 | def start_async(_client) 53 | fail NotImplementedError, "Expected #{self.class} to implement #{__method__}." 54 | end 55 | 56 | def close 57 | @driver = nil 58 | end 59 | 60 | protected 61 | 62 | def addr 63 | URI(url).host 64 | end 65 | 66 | def secure? 67 | port == URI::HTTPS::DEFAULT_PORT 68 | end 69 | 70 | def port 71 | case (uri = URI(url)).scheme 72 | when 'wss'.freeze, 'https'.freeze 73 | URI::HTTPS::DEFAULT_PORT 74 | when 'ws', 'http'.freeze 75 | URI::HTTP::DEFAULT_PORT 76 | else 77 | uri.port 78 | end 79 | end 80 | 81 | def connect 82 | fail NotImplementedError, "Expected #{self.class} to implement #{__method__}." 83 | end 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /spec/fixtures/slack/web/429_error.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: https://slack.com/api/auth.test 6 | body: 7 | encoding: UTF-8 8 | string: token= 9 | headers: 10 | Accept: 11 | - application/json; charset=utf-8 12 | User-Agent: 13 | - Slack Ruby Client 0.1.0 14 | Content-Type: 15 | - application/x-www-form-urlencoded 16 | Accept-Encoding: 17 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 18 | response: 19 | status: 20 | code: 429 21 | message: OK 22 | headers: 23 | Access-Control-Allow-Origin: 24 | - '*' 25 | Date: 26 | - Sat, 25 Jul 2015 14:42:07 GMT 27 | Server: 28 | - Apache 29 | Connection: 30 | - keep-alive 31 | body: 32 | encoding: US-ASCII 33 | string: '' 34 | http_version: 35 | recorded_at: Sat, 25 Jul 2015 14:42:08 GMT 36 | - request: 37 | method: post 38 | uri: https://slack.com/api/auth.test 39 | body: 40 | encoding: UTF-8 41 | string: token 42 | headers: 43 | Accept: 44 | - application/json; charset=utf-8 45 | User-Agent: 46 | - Slack Ruby Client/0.5.0 47 | Content-Type: 48 | - application/x-www-form-urlencoded 49 | Accept-Encoding: 50 | - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 51 | response: 52 | status: 53 | code: 200 54 | message: OK 55 | headers: 56 | Access-Control-Allow-Origin: 57 | - '*' 58 | Content-Security-Policy: 59 | - referrer no-referrer; 60 | Content-Type: 61 | - application/json; charset=utf-8 62 | Date: 63 | - Tue, 24 Nov 2015 20:03:05 GMT 64 | Server: 65 | - Apache 66 | Strict-Transport-Security: 67 | - max-age=31536000; includeSubDomains; preload 68 | X-Accepted-Oauth-Scopes: 69 | - identify 70 | X-Content-Type-Options: 71 | - nosniff 72 | X-Xss-Protection: 73 | - '0' 74 | Content-Length: 75 | - '33' 76 | Connection: 77 | - keep-alive 78 | body: 79 | encoding: UTF-8 80 | string: '{"ok":false,"error":"not_authed"}' 81 | http_version: 82 | recorded_at: Tue, 24 Nov 2015 20:03:05 GMT 83 | recorded_with: VCR 2.9.3 84 | -------------------------------------------------------------------------------- /spec/slack/slack_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Slack do 4 | let(:slack) { File.expand_path(File.join(__FILE__, '../../../bin/slack')) } 5 | before do 6 | @token = ENV.delete('SLACK_API_TOKEN') 7 | end 8 | after do 9 | ENV['SLACK_API_TOKEN'] = @token if @token 10 | end 11 | describe '#help' do 12 | it 'displays help' do 13 | help = `"#{slack}" help` 14 | expect(help).to include 'slack - Slack client.' 15 | end 16 | end 17 | context 'globals' do 18 | it 'enables request and response logging with -d' do 19 | output = `"#{slack}" --vcr-cassette-name=web/auth_test_success --slack-api-token=token -d auth test 2>&1` 20 | expect(output).to include 'post https://slack.com/api/auth.test' 21 | expect(output).to include 'Status: 200' 22 | end 23 | it 'requires --slack-api-token' do 24 | err = `"#{slack}" auth test 2>&1` 25 | expect(err).to start_with 'error: parse error: Set Slack API token via --slack-api-token or SLACK_API_TOKEN.' 26 | end 27 | end 28 | describe '#auth' do 29 | context 'bad auth' do 30 | it 'fails with an exception' do 31 | err = `"#{slack}" --vcr-cassette-name=web/auth_test_error --slack-api-token=token auth test 2>&1` 32 | expect(err).to eq "error: not_authed\n" 33 | end 34 | end 35 | context 'good auth' do 36 | it 'succeeds' do 37 | json = Slack::Messages::Message.new(JSON.parse(`"#{slack}" --vcr-cassette-name=web/auth_test_success --slack-api-token=token auth test 2>&1`)) 38 | expect(json).to eq( 39 | 'ok' => true, 40 | 'url' => 'https://rubybot.slack.com/', 41 | 'team' => 'team_name', 42 | 'user' => 'user_name', 43 | 'team_id' => 'TDEADBEEF', 44 | 'user_id' => 'UBAADFOOD' 45 | ) 46 | expect(json.ok).to be true 47 | end 48 | end 49 | end 50 | describe '#users' do 51 | it 'list' do 52 | json = Slack::Messages::Message.new(JSON.parse(`"#{slack}" --vcr-cassette-name=web/users_list --slack-api-token=token users list --presence=true 2>&1`)) 53 | expect(json.ok).to be true 54 | expect(json.members.size).to eq 9 55 | expect(json.members.first['presence']).to eq 'away' 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /bin/commands/team.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Team methods.' 4 | command 'team' do |g| 5 | g.desc 'This method is used to get the access logs for users on a team.' 6 | g.long_desc %( This method is used to get the access logs for users on a team. ) 7 | g.command 'accessLogs' do |c| 8 | c.action do |_global_options, options, _args| 9 | puts JSON.dump($client.team_accessLogs(options)) 10 | end 11 | end 12 | 13 | g.desc 'This method lists billable information for each user on the team. Currently this consists solely of whether the user is' 14 | g.long_desc %( This method lists billable information for each user on the team. Currently this consists solely of whether the user is subject to billing per Slack's Fair Billing policy. ) 15 | g.command 'billableInfo' do |c| 16 | c.flag 'user', desc: 'A user to retrieve the billable information for. Defaults to all users.' 17 | c.action do |_global_options, options, _args| 18 | puts JSON.dump($client.team_billableInfo(options)) 19 | end 20 | end 21 | 22 | g.desc 'This method provides information about your team.' 23 | g.long_desc %( This method provides information about your team. ) 24 | g.command 'info' do |c| 25 | c.action do |_global_options, options, _args| 26 | puts JSON.dump($client.team_info(options)) 27 | end 28 | end 29 | 30 | g.desc 'This method lists the integration activity logs for a team, including when integrations are added, modified and removed. This method can only be called by Admins.' 31 | g.long_desc %( This method lists the integration activity logs for a team, including when integrations are added, modified and removed. This method can only be called by Admins. ) 32 | g.command 'integrationLogs' do |c| 33 | c.flag 'service_id', desc: 'Filter logs to this service. Defaults to all logs.' 34 | c.flag 'app_id', desc: 'Filter logs to this Slack app. Defaults to all logs.' 35 | c.flag 'user', desc: "Filter logs generated by this user's actions. Defaults to all logs." 36 | c.flag 'change_type', desc: 'Filter logs with this change type. Defaults to all logs.' 37 | c.action do |_global_options, options, _args| 38 | puts JSON.dump($client.team_integrationLogs(options)) 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/slack/real_time/event_handlers/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | context 'user' do 7 | it 'combines user and self data on rtm.start' do 8 | expect(client.users['U07518DTL'].name).to eq 'rubybot' 9 | expect(client.users['U07518DTL']['prefs']['push_sound']).to eq 'b2.mp3' 10 | end 11 | it 'user_change' do 12 | expect(client.users['U07KECJ77'].name).to eq 'aws' 13 | event = Slack::RealTime::Event.new( 14 | 'type' => 'user_change', 15 | 'user' => { 16 | 'id' => 'U07KECJ77', 'name' => 'renamed' 17 | }) 18 | client.send(:dispatch, event) 19 | expect(client.users['U07KECJ77'].name).to eq 'renamed' 20 | end 21 | it 'team_join' do 22 | expect do 23 | event = Slack::RealTime::Event.new( 24 | 'type' => 'team_join', 25 | 'user' => { 26 | 'id' => 'DEADBEEF', 'name' => 'added' 27 | }) 28 | client.send(:dispatch, event) 29 | end.to change(client.users, :count).by(1) 30 | expect(client.users['DEADBEEF'].name).to eq 'added' 31 | end 32 | it 'pref_change' do 33 | event = Slack::RealTime::Event.new( 34 | 'type' => 'pref_change', 35 | 'name' => 'push_sound', 36 | 'value' => 'updated.mp3' 37 | ) 38 | client.send(:dispatch, event) 39 | expect(client.self.prefs['push_sound']).to eq 'updated.mp3' 40 | end 41 | it 'presence_change' do 42 | expect(client.users['U07KECJ77'].presence).to eq 'away' 43 | event = Slack::RealTime::Event.new( 44 | 'type' => 'presence_change', 45 | 'user' => 'U07KECJ77', 46 | 'presence' => 'updated' 47 | ) 48 | client.send(:dispatch, event) 49 | expect(client.users['U07KECJ77'].presence).to eq 'updated' 50 | end 51 | it 'manual_presence_change' do 52 | expect(client.self['presence']).to eq 'away' 53 | event = Slack::RealTime::Event.new( 54 | 'type' => 'manual_presence_change', 55 | 'presence' => 'updated' 56 | ) 57 | client.send(:dispatch, event) 58 | expect(client.self.presence).to eq 'updated' 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /spec/slack/real_time/event_handlers/team_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | [Slack::RealTime::Stores::Store, Slack::RealTime::Stores::Starter].each do |store_class| 4 | RSpec.describe store_class, vcr: { cassette_name: 'web/rtm_start' } do 5 | include_context 'connected client', store_class: store_class 6 | 7 | context 'team' do 8 | it 'sets team data on rtm.start' do 9 | expect(client.team.name).to eq 'dblock' 10 | expect(client.team.domain).to eq 'dblockdotorg' 11 | expect(client.team.email_domain).to eq 'dblock.org' 12 | expect(client.team.prefs.invites_only_admins).to be true 13 | expect(client.team.plan).to eq '' 14 | end 15 | it 'team_domain_change' do 16 | event = Slack::RealTime::Event.new( 17 | 'type' => 'team_domain_change', 18 | 'url' => 'https://my.slack.com', 19 | 'domain' => 'my' 20 | ) 21 | client.send(:dispatch, event) 22 | expect(client.team.domain).to eq 'my' 23 | expect(client.team['url']).to eq 'https://my.slack.com' 24 | end 25 | it 'email_domain_changed' do 26 | event = Slack::RealTime::Event.new( 27 | 'type' => 'email_domain_changed', 28 | 'email_domain' => 'example.com' 29 | ) 30 | client.send(:dispatch, event) 31 | expect(client.team.email_domain).to eq 'example.com' 32 | end 33 | it 'team_pref_change' do 34 | event = Slack::RealTime::Event.new( 35 | 'type' => 'team_pref_change', 36 | 'name' => 'invites_only_admins', 37 | 'value' => false 38 | ) 39 | client.send(:dispatch, event) 40 | expect(client.team.prefs.invites_only_admins).to be false 41 | end 42 | it 'team_rename' do 43 | event = Slack::RealTime::Event.new( 44 | 'type' => 'team_rename', 45 | 'name' => 'New Team Name Inc.' 46 | ) 47 | client.send(:dispatch, event) 48 | expect(client.team.name).to eq 'New Team Name Inc.' 49 | end 50 | it 'team_plan_change' do 51 | event = Slack::RealTime::Event.new( 52 | 'type' => 'team_plan_change', 53 | 'plan' => 'std' 54 | ) 55 | client.send(:dispatch, event) 56 | expect(client.team.plan).to eq 'std' 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2016-05-03 16:35:06 -0400 using RuboCop version 0.35.0. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 4 10 | Lint/HandleExceptions: 11 | Exclude: 12 | - 'lib/slack-ruby-client.rb' 13 | - 'lib/slack/real_time/concurrency/celluloid.rb' 14 | - 'spec/slack/real_time/concurrency/celluloid_spec.rb' 15 | - 'spec/slack/real_time/concurrency/eventmachine_spec.rb' 16 | 17 | # Offense count: 1 18 | # Cop supports --auto-correct. 19 | # Configuration parameters: IgnoreEmptyBlocks. 20 | Lint/UnusedBlockArgument: 21 | Exclude: 22 | - 'lib/slack/messages/formatting.rb' 23 | 24 | # Offense count: 15 25 | Metrics/AbcSize: 26 | Max: 44 27 | 28 | # Offense count: 2 29 | # Configuration parameters: CountComments. 30 | Metrics/ClassLength: 31 | Max: 156 32 | 33 | # Offense count: 2 34 | Metrics/CyclomaticComplexity: 35 | Max: 9 36 | 37 | # Offense count: 595 38 | # Configuration parameters: AllowURI, URISchemes. 39 | Metrics/LineLength: 40 | Max: 288 41 | 42 | # Offense count: 7 43 | # Configuration parameters: CountComments. 44 | Metrics/MethodLength: 45 | Max: 32 46 | 47 | # Offense count: 2 48 | Metrics/PerceivedComplexity: 49 | Max: 11 50 | 51 | # Offense count: 55 52 | # Configuration parameters: Exclude. 53 | Style/Documentation: 54 | Enabled: false 55 | 56 | # Offense count: 1 57 | # Configuration parameters: Exclude. 58 | Style/FileName: 59 | Exclude: 60 | - 'lib/slack-ruby-client.rb' 61 | 62 | # Offense count: 100 63 | # Configuration parameters: AllowedVariables. 64 | Style/GlobalVars: 65 | Enabled: false 66 | 67 | # Offense count: 17 68 | # Configuration parameters: EnforcedStyle, SupportedStyles. 69 | Style/MethodName: 70 | Enabled: false 71 | 72 | # Offense count: 3 73 | Style/ModuleFunction: 74 | Exclude: 75 | - 'lib/slack/config.rb' 76 | - 'lib/slack/real_time/config.rb' 77 | - 'lib/slack/web/config.rb' 78 | 79 | # Offense count: 2 80 | # Cop supports --auto-correct. 81 | Style/SpecialGlobalVars: 82 | Exclude: 83 | - 'lib/slack/messages/formatting.rb' 84 | -------------------------------------------------------------------------------- /bin/commands/dnd.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Adjust and view Do Not Disturb settings for team members.' 4 | command 'dnd' do |g| 5 | g.desc "Ends the user's currently scheduled Do Not Disturb session immediately." 6 | g.long_desc %( Ends the user's currently scheduled Do Not Disturb session immediately. ) 7 | g.command 'endDnd' do |c| 8 | c.action do |_global_options, options, _args| 9 | puts JSON.dump($client.dnd_endDnd(options)) 10 | end 11 | end 12 | 13 | g.desc "Ends the current user's snooze mode immediately." 14 | g.long_desc %( Ends the current user's snooze mode immediately. ) 15 | g.command 'endSnooze' do |c| 16 | c.action do |_global_options, options, _args| 17 | puts JSON.dump($client.dnd_endSnooze(options)) 18 | end 19 | end 20 | 21 | g.desc "Provides information about a user's current Do Not Disturb settings." 22 | g.long_desc %( Provides information about a user's current Do Not Disturb settings. ) 23 | g.command 'info' do |c| 24 | c.flag 'user', desc: 'User to fetch status for (defaults to current user).' 25 | c.action do |_global_options, options, _args| 26 | puts JSON.dump($client.dnd_info(options)) 27 | end 28 | end 29 | 30 | g.desc "Adjusts the snooze duration for a user's Do Not Disturb settings. If a snooze session is not already active for the user, invoking this method will begin one for the specified duration." 31 | g.long_desc %( Adjusts the snooze duration for a user's Do Not Disturb settings. If a snooze session is not already active for the user, invoking this method will begin one for the specified duration. ) 32 | g.command 'setSnooze' do |c| 33 | c.flag 'num_minutes', desc: 'Number of minutes, from now, to snooze until.' 34 | c.action do |_global_options, options, _args| 35 | puts JSON.dump($client.dnd_setSnooze(options)) 36 | end 37 | end 38 | 39 | g.desc 'Provides information about the current Do Not Disturb settings for users of a Slack team.' 40 | g.long_desc %( Provides information about the current Do Not Disturb settings for users of a Slack team. ) 41 | g.command 'teamInfo' do |c| 42 | c.flag 'users', desc: 'Comma-separated list of users to fetch Do Not Disturb status for.' 43 | c.action do |_global_options, options, _args| 44 | puts JSON.dump($client.dnd_teamInfo(options)) 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /UPGRADING.md: -------------------------------------------------------------------------------- 1 | Upgrading Slack-Ruby-Client 2 | =========================== 3 | 4 | ### Upgrading to >= 0.6.0 5 | 6 | #### Changes to API Response Data 7 | 8 | API responses in both Web and RealTime clients are now instances of [Slack::Messages::Message](lib/slack/messages/message.rb), which provides method access to properties. 9 | 10 | Before: 11 | 12 | ```ruby 13 | puts "Welcome '#{client.self['name']}' to the '#{client.team['name']}' team." 14 | ``` 15 | 16 | After: 17 | 18 | ```ruby 19 | puts "Welcome #{client.self.name} to the #{client.team.name} team." 20 | ``` 21 | 22 | See [#56](https://github.com/slack-ruby/slack-ruby-client/issues/56) for more information. 23 | 24 | #### Changes to RealTime Local Store 25 | 26 | Upon a successful `rtm.start` the RealTime client keeps a local cache of objects, including `self` or `users`. It will now also track changes to these objects. The following changes have been made to the data structures. 27 | 28 | ##### client.self 29 | 30 | The `client.self` object is now a `Slack::RealTime::Models::User`, which is a child of `Hashie::Mash`, so no code changes should be required. 31 | 32 | ##### client.team 33 | 34 | The `client.team` object is now a `Slack::RealTime::Models::Team`, which is a child of `Hashie::Mash`, so no code changes should be required. 35 | 36 | ##### client .users, .channels, .groups, .ims 37 | 38 | The `client.users`, `.channels`, `.groups` and `.ims` collections have been changed from `Array` to `Hash`, with object ID as key. Replace any code iterating over the array, eg. `client.users.values.each` or `client.channels.each_pair { |id, channel| ... }`. 39 | 40 | See [#55](https://github.com/slack-ruby/slack-ruby-client/issues/55) for more information. 41 | 42 | ### Upgrading to >= 0.5.0 43 | 44 | #### Changes to Real Time Concurrency 45 | 46 | Since 0.5.0 `Slack::RealTime::Client` supports [Celluloid](https://github.com/celluloid/celluloid) and no longer defaults to [Faye::WebSocket](https://github.com/faye/faye-websocket-ruby) with [Eventmachine](https://github.com/eventmachine/eventmachine). It will auto-detect one or the other depending on the gems in your Gemfile, which means you may need to add one or the other to your Gemfile. 47 | 48 | ##### Faye::WebSocket with Eventmachine 49 | 50 | ``` 51 | gem 'faye-websocket' 52 | ``` 53 | 54 | ##### Celluloid 55 | 56 | ``` 57 | gem 'celluloid-io' 58 | ``` 59 | 60 | When in doubt, use `faye-websocket`. 61 | 62 | See [#5](https://github.com/slack-ruby/slack-ruby-client/issues/5) for more information. 63 | 64 | 65 | -------------------------------------------------------------------------------- /spec/fixtures/slack/web/channels_info.yml: -------------------------------------------------------------------------------- 1 | --- 2 | http_interactions: 3 | - request: 4 | method: post 5 | uri: https://slack.com/api/channels.list 6 | body: 7 | encoding: UTF-8 8 | string: token=token 9 | response: 10 | status: 11 | code: 200 12 | message: OK 13 | headers: 14 | Content-Type: 15 | - application/json; charset=utf-8 16 | body: 17 | encoding: UTF-8 18 | string: '{"ok":true,"channels":[{"id":"C04KB5X4D","name":"general","is_channel":true,"created":1430222230,"creator":"U04KB5WQR","is_archived":false,"is_general":true,"is_member":true,"last_read":"1435863302.000026","latest":{"type":"message","user":"U0HPMN0GY","text":"```\n{\"ok\":true,\"args\":{\"token\":\"xoxb-17803748576-H794PZkqOo4DkjYddb438F2J\"}}```","ts":"1452025068.000045"},"unread_count":321,"unread_count_display":283,"members":["U04JPQ0JS","U04JZBDQQ","U04KB5WQR"],"topic":{"value":"","creator":"","last_set":0},"purpose":{"value":"This 19 | channel is for team-wide communication and announcements. All team members 20 | are in this channel.","creator":"","last_set":0}}]}' 21 | http_version: 22 | recorded_at: Fri, 22 Jan 2016 19:01:46 GMT 23 | - request: 24 | method: post 25 | uri: https://slack.com/api/channels.info 26 | body: 27 | encoding: UTF-8 28 | string: channel=C04KB5X4D&token=token 29 | headers: 30 | Content-Type: 31 | - application/x-www-form-urlencoded 32 | response: 33 | status: 34 | code: 200 35 | message: OK 36 | headers: 37 | Content-Type: 38 | - application/json; charset=utf-8 39 | body: 40 | encoding: UTF-8 41 | string: '{"ok":true,"channel":{"id":"C04KB5X4D","name":"general","is_channel":true,"created":1430222230,"creator":"U04KB5WQR","is_archived":false,"is_general":true,"is_member":true,"last_read":"1435863302.000026","latest":{"type":"message","user":"U0HPMN0GY","text":"```\n{\"ok\":true,\"args\":{\"token\":\"xoxb-17803748576-H794PZkqOo4DkjYddb438F2J\"}}```","ts":"1452025068.000045"},"unread_count":321,"unread_count_display":283,"members":["U04JPQ0JS","U04JZBDQQ","U04KB5WQR","U06JGTU5V","U07518DTL","U07KECJ77","U092BDCLV","U092V4E9L","U0EA7TZJN","U0H701CJZ","U0HLFUZLJ","U0HPMN0GY"],"topic":{"value":"","creator":"","last_set":0},"purpose":{"value":"This 42 | channel is for team-wide communication and announcements. All team members 43 | are in this channel.","creator":"","last_set":0}}}' 44 | http_version: 45 | recorded_at: Fri, 22 Jan 2016 19:01:46 GMT 46 | recorded_with: VCR 3.0.1 47 | -------------------------------------------------------------------------------- /bin/commands/im.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Get info on your direct messages.' 4 | command 'im' do |g| 5 | g.desc 'This method closes a direct message channel.' 6 | g.long_desc %( This method closes a direct message channel. ) 7 | g.command 'close' do |c| 8 | c.flag 'channel', desc: 'Direct message channel to close.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.im_close(options)) 11 | end 12 | end 13 | 14 | g.desc 'This method returns a portion of messages/events from the specified direct message channel.' 15 | g.long_desc %( This method returns a portion of messages/events from the specified direct message channel. To read the entire history for a direct message channel, call the method with no latest or oldest arguments, and then continue paging using the instructions below. ) 16 | g.command 'history' do |c| 17 | c.flag 'channel', desc: 'Direct message channel to fetch history for.' 18 | c.flag 'latest', desc: 'End of time range of messages to include in results.' 19 | c.flag 'oldest', desc: 'Start of time range of messages to include in results.' 20 | c.flag 'inclusive', desc: 'Include messages with latest or oldest timestamp in results.' 21 | c.flag 'unreads', desc: 'Include unread_count_display in the output?.' 22 | c.action do |_global_options, options, _args| 23 | puts JSON.dump($client.im_history(options)) 24 | end 25 | end 26 | 27 | g.desc 'This method returns a list of all im channels that the user has.' 28 | g.long_desc %( This method returns a list of all im channels that the user has. ) 29 | g.command 'list' do |c| 30 | c.action do |_global_options, options, _args| 31 | puts JSON.dump($client.im_list(options)) 32 | end 33 | end 34 | 35 | g.desc 'This method moves the read cursor in a direct message channel.' 36 | g.long_desc %( This method moves the read cursor in a direct message channel. ) 37 | g.command 'mark' do |c| 38 | c.flag 'channel', desc: 'Direct message channel to set reading cursor in.' 39 | c.flag 'ts', desc: 'Timestamp of the most recently seen message.' 40 | c.action do |_global_options, options, _args| 41 | puts JSON.dump($client.im_mark(options)) 42 | end 43 | end 44 | 45 | g.desc 'This method opens a direct message channel with another member of your Slack team.' 46 | g.long_desc %( This method opens a direct message channel with another member of your Slack team. ) 47 | g.command 'open' do |c| 48 | c.flag 'user', desc: 'User to open a direct message channel with.' 49 | c.flag 'return_im', desc: 'Boolean, indicates you want the full IM channel definition in the response.' 50 | c.action do |_global_options, options, _args| 51 | puts JSON.dump($client.im_open(options)) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /bin/commands/mpim.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Get info on your multiparty direct messages.' 4 | command 'mpim' do |g| 5 | g.desc 'This method closes a multiparty direct message channel.' 6 | g.long_desc %( This method closes a multiparty direct message channel. ) 7 | g.command 'close' do |c| 8 | c.flag 'channel', desc: 'MPIM to close.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.mpim_close(options)) 11 | end 12 | end 13 | 14 | g.desc 'This method returns a portion of messages/events from the specified multiparty direct message channel.' 15 | g.long_desc %( This method returns a portion of messages/events from the specified multiparty direct message channel. To read the entire history for a multiparty direct message, call the method with no latest or oldest arguments, and then continue paging using the instructions below. ) 16 | g.command 'history' do |c| 17 | c.flag 'channel', desc: 'Multiparty direct message to fetch history for.' 18 | c.flag 'latest', desc: 'End of time range of messages to include in results.' 19 | c.flag 'oldest', desc: 'Start of time range of messages to include in results.' 20 | c.flag 'inclusive', desc: 'Include messages with latest or oldest timestamp in results.' 21 | c.flag 'unreads', desc: 'Include unread_count_display in the output?.' 22 | c.action do |_global_options, options, _args| 23 | puts JSON.dump($client.mpim_history(options)) 24 | end 25 | end 26 | 27 | g.desc 'This method returns a list of all multiparty direct message channels that the user has.' 28 | g.long_desc %( This method returns a list of all multiparty direct message channels that the user has. ) 29 | g.command 'list' do |c| 30 | c.action do |_global_options, options, _args| 31 | puts JSON.dump($client.mpim_list(options)) 32 | end 33 | end 34 | 35 | g.desc 'This method moves the read cursor in a multiparty direct message channel.' 36 | g.long_desc %( This method moves the read cursor in a multiparty direct message channel. ) 37 | g.command 'mark' do |c| 38 | c.flag 'channel', desc: 'multiparty direct message channel to set reading cursor in.' 39 | c.flag 'ts', desc: 'Timestamp of the most recently seen message.' 40 | c.action do |_global_options, options, _args| 41 | puts JSON.dump($client.mpim_mark(options)) 42 | end 43 | end 44 | 45 | g.desc 'This method opens a multiparty direct message.' 46 | g.long_desc %( This method opens a multiparty direct message. ) 47 | g.command 'open' do |c| 48 | c.flag 'users', desc: 'Comma separated lists of users. The ordering of the users is preserved whenever a MPIM group is returned.' 49 | c.action do |_global_options, options, _args| 50 | puts JSON.dump($client.mpim_open(options)) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/team.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Team 8 | # 9 | # This method is used to get the access logs for users on a team. 10 | # 11 | # @see https://api.slack.com/methods/team.accessLogs 12 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/team/team.accessLogs.json 13 | def team_accessLogs(options = {}) 14 | post('team.accessLogs', options) 15 | end 16 | 17 | # 18 | # This method lists billable information for each user on the team. Currently this consists solely of whether the user is 19 | # subject to billing per Slack's Fair Billing policy. 20 | # 21 | # @option options [user] :user 22 | # A user to retrieve the billable information for. Defaults to all users. 23 | # @see https://api.slack.com/methods/team.billableInfo 24 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/team/team.billableInfo.json 25 | def team_billableInfo(options = {}) 26 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 27 | post('team.billableInfo', options) 28 | end 29 | 30 | # 31 | # This method provides information about your team. 32 | # 33 | # @see https://api.slack.com/methods/team.info 34 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/team/team.info.json 35 | def team_info(options = {}) 36 | post('team.info', options) 37 | end 38 | 39 | # 40 | # This method lists the integration activity logs for a team, including when integrations are added, modified and removed. This method can only be called by Admins. 41 | # 42 | # @option options [Object] :service_id 43 | # Filter logs to this service. Defaults to all logs. 44 | # @option options [Object] :app_id 45 | # Filter logs to this Slack app. Defaults to all logs. 46 | # @option options [user] :user 47 | # Filter logs generated by this user's actions. Defaults to all logs. 48 | # @option options [Object] :change_type 49 | # Filter logs with this change type. Defaults to all logs. 50 | # @see https://api.slack.com/methods/team.integrationLogs 51 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/team/team.integrationLogs.json 52 | def team_integrationLogs(options = {}) 53 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 54 | post('team.integrationLogs', options) 55 | end 56 | end 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/dnd.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Dnd 8 | # 9 | # Ends the user's currently scheduled Do Not Disturb session immediately. 10 | # 11 | # @see https://api.slack.com/methods/dnd.endDnd 12 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/dnd/dnd.endDnd.json 13 | def dnd_endDnd(options = {}) 14 | post('dnd.endDnd', options) 15 | end 16 | 17 | # 18 | # Ends the current user's snooze mode immediately. 19 | # 20 | # @see https://api.slack.com/methods/dnd.endSnooze 21 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/dnd/dnd.endSnooze.json 22 | def dnd_endSnooze(options = {}) 23 | post('dnd.endSnooze', options) 24 | end 25 | 26 | # 27 | # Provides information about a user's current Do Not Disturb settings. 28 | # 29 | # @option options [user] :user 30 | # User to fetch status for (defaults to current user). 31 | # @see https://api.slack.com/methods/dnd.info 32 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/dnd/dnd.info.json 33 | def dnd_info(options = {}) 34 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 35 | post('dnd.info', options) 36 | end 37 | 38 | # 39 | # Adjusts the snooze duration for a user's Do Not Disturb settings. If a snooze session is not already active for the user, invoking this method will begin one for the specified duration. 40 | # 41 | # @option options [Object] :num_minutes 42 | # Number of minutes, from now, to snooze until. 43 | # @see https://api.slack.com/methods/dnd.setSnooze 44 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/dnd/dnd.setSnooze.json 45 | def dnd_setSnooze(options = {}) 46 | throw ArgumentError.new('Required arguments :num_minutes missing') if options[:num_minutes].nil? 47 | post('dnd.setSnooze', options) 48 | end 49 | 50 | # 51 | # Provides information about the current Do Not Disturb settings for users of a Slack team. 52 | # 53 | # @option options [Object] :users 54 | # Comma-separated list of users to fetch Do Not Disturb status for. 55 | # @see https://api.slack.com/methods/dnd.teamInfo 56 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/dnd/dnd.teamInfo.json 57 | def dnd_teamInfo(options = {}) 58 | post('dnd.teamInfo', options) 59 | end 60 | end 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/stars.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Stars 8 | # 9 | # This method adds a star to an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user. 10 | # One of file, file_comment, channel, or the combination of channel and timestamp must be specified. 11 | # 12 | # @option options [file] :file 13 | # File to add star to. 14 | # @option options [Object] :file_comment 15 | # File comment to add star to. 16 | # @option options [channel] :channel 17 | # Channel to add star to, or channel where the message to add star to was posted (used with timestamp). 18 | # @option options [Object] :timestamp 19 | # Timestamp of the message to add star to. 20 | # @see https://api.slack.com/methods/stars.add 21 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/stars/stars.add.json 22 | def stars_add(options = {}) 23 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 24 | post('stars.add', options) 25 | end 26 | 27 | # 28 | # This method lists the items starred by the authed user. 29 | # 30 | # @see https://api.slack.com/methods/stars.list 31 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/stars/stars.list.json 32 | def stars_list(options = {}) 33 | post('stars.list', options) 34 | end 35 | 36 | # 37 | # This method removes a star from an item (message, file, file comment, channel, private group, or DM) on behalf of the authenticated user. 38 | # One of file, file_comment, channel, or the combination of channel and timestamp must be specified. 39 | # 40 | # @option options [file] :file 41 | # File to remove star from. 42 | # @option options [Object] :file_comment 43 | # File comment to remove star from. 44 | # @option options [channel] :channel 45 | # Channel to remove star from, or channel where the message to remove star from was posted (used with timestamp). 46 | # @option options [Object] :timestamp 47 | # Timestamp of the message to remove star from. 48 | # @see https://api.slack.com/methods/stars.remove 49 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/stars/stars.remove.json 50 | def stars_remove(options = {}) 51 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 52 | post('stars.remove', options) 53 | end 54 | end 55 | end 56 | end 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /spec/slack/real_time/event_handlers/group_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::RealTime::Client, vcr: { cassette_name: 'web/rtm_start' } do 4 | include_context 'connected client' 5 | 6 | context 'group' do 7 | it 'sets group data' do 8 | expect(client.groups.count).to eq 1 9 | end 10 | it 'group_joined' do 11 | expect(client.groups['CDEADBEEF']).to be nil 12 | event = Slack::RealTime::Event.new( 13 | 'type' => 'group_joined', 14 | 'channel' => { 15 | 'id' => 'CDEADBEEF', 16 | 'name' => 'beef' 17 | } 18 | ) 19 | client.send(:dispatch, event) 20 | group = client.groups['CDEADBEEF'] 21 | expect(group).to_not be nil 22 | expect(group.name).to eq 'beef' 23 | end 24 | it 'group_left' do 25 | group = client.groups['G0K7EV5A7'] 26 | expect(group.members).to include client.self.id 27 | event = Slack::RealTime::Event.new( 28 | 'type' => 'group_left', 29 | 'channel' => 'G0K7EV5A7' 30 | ) 31 | client.send(:dispatch, event) 32 | expect(group.members).to_not include client.self.id 33 | end 34 | it 'group_archive' do 35 | group = client.groups['G0K7EV5A7'] 36 | expect(group.is_archived).to be false 37 | event = Slack::RealTime::Event.new( 38 | 'type' => 'group_archive', 39 | 'channel' => 'G0K7EV5A7' 40 | ) 41 | client.send(:dispatch, event) 42 | expect(group.is_archived).to be true 43 | end 44 | it 'group_unarchive' do 45 | group = client.groups['G0K7EV5A7'] 46 | group.is_archived = true 47 | event = Slack::RealTime::Event.new( 48 | 'type' => 'group_unarchive', 49 | 'channel' => 'G0K7EV5A7' 50 | ) 51 | client.send(:dispatch, event) 52 | expect(group.is_archived).to be false 53 | end 54 | it 'group_rename' do 55 | group = client.groups['G0K7EV5A7'] 56 | expect(group.name).to eq 'mpdm-dblock--rubybot--player1-1' 57 | event = Slack::RealTime::Event.new( 58 | 'type' => 'group_rename', 59 | 'channel' => { 60 | 'id' => 'G0K7EV5A7', 61 | 'name' => 'updated', 62 | 'created' => 1_360_782_804 63 | } 64 | ) 65 | client.send(:dispatch, event) 66 | expect(group.name).to eq 'updated' 67 | end 68 | it 'group_open' do 69 | group = client.groups['G0K7EV5A7'] 70 | expect(group).to_not be_nil 71 | event = Slack::RealTime::Event.new( 72 | 'type' => 'group_open', 73 | 'channel' => 'G0K7EV5A7' 74 | ) 75 | client.send(:dispatch, event) 76 | expect(group.is_open).to be true 77 | end 78 | it 'group_close' do 79 | group = client.groups['G0K7EV5A7'] 80 | expect(group).to_not be_nil 81 | group.is_open = true 82 | event = Slack::RealTime::Event.new( 83 | 'type' => 'group_close', 84 | 'channel' => 'G0K7EV5A7' 85 | ) 86 | client.send(:dispatch, event) 87 | expect(group.is_open).to be false 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/pins.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Pins 8 | # 9 | # This method pins an item (file, file comment, channel message, or group message) to a particular channel. 10 | # The channel argument is required and one of file, file_comment, or timestamp must also be specified. 11 | # 12 | # @option options [channel] :channel 13 | # Channel to pin the item in. 14 | # @option options [file] :file 15 | # File to pin. 16 | # @option options [Object] :file_comment 17 | # File comment to pin. 18 | # @option options [Object] :timestamp 19 | # Timestamp of the message to pin. 20 | # @see https://api.slack.com/methods/pins.add 21 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/pins/pins.add.json 22 | def pins_add(options = {}) 23 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 24 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 25 | post('pins.add', options) 26 | end 27 | 28 | # 29 | # This method lists the items pinned to a channel. 30 | # 31 | # @option options [channel] :channel 32 | # Channel to get pinned items for. 33 | # @see https://api.slack.com/methods/pins.list 34 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/pins/pins.list.json 35 | def pins_list(options = {}) 36 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 37 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 38 | post('pins.list', options) 39 | end 40 | 41 | # 42 | # This method un-pins an item (file, file comment, channel message, or group message) from a channel. 43 | # The channel argument is required and one of file, file_comment, or timestamp must also be specified. 44 | # 45 | # @option options [channel] :channel 46 | # Channel where the item is pinned to. 47 | # @option options [file] :file 48 | # File to un-pin. 49 | # @option options [Object] :file_comment 50 | # File comment to un-pin. 51 | # @option options [Object] :timestamp 52 | # Timestamp of the message to un-pin. 53 | # @see https://api.slack.com/methods/pins.remove 54 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/pins/pins.remove.json 55 | def pins_remove(options = {}) 56 | throw ArgumentError.new('Required arguments :channel missing') if options[:channel].nil? 57 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 58 | post('pins.remove', options) 59 | end 60 | end 61 | end 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/search.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Search 8 | # 9 | # This method allows users and applications to search both messages and files in a single call. 10 | # 11 | # @option options [Object] :query 12 | # Search query. May contains booleans, etc. 13 | # @option options [Object] :sort 14 | # Return matches sorted by either score or timestamp. 15 | # @option options [Object] :sort_dir 16 | # Change sort direction to ascending (asc) or descending (desc). 17 | # @option options [Object] :highlight 18 | # Pass a value of 1 to enable query highlight markers (see below). 19 | # @see https://api.slack.com/methods/search.all 20 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/search/search.all.json 21 | def search_all(options = {}) 22 | throw ArgumentError.new('Required arguments :query missing') if options[:query].nil? 23 | post('search.all', options) 24 | end 25 | 26 | # 27 | # This method returns files matching a search query. 28 | # 29 | # @option options [Object] :query 30 | # Search query. May contain booleans, etc. 31 | # @option options [Object] :sort 32 | # Return matches sorted by either score or timestamp. 33 | # @option options [Object] :sort_dir 34 | # Change sort direction to ascending (asc) or descending (desc). 35 | # @option options [Object] :highlight 36 | # Pass a value of 1 to enable query highlight markers (see below). 37 | # @see https://api.slack.com/methods/search.files 38 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/search/search.files.json 39 | def search_files(options = {}) 40 | throw ArgumentError.new('Required arguments :query missing') if options[:query].nil? 41 | post('search.files', options) 42 | end 43 | 44 | # 45 | # This method returns messages matching a search query. 46 | # 47 | # @option options [Object] :query 48 | # Search query. May contains booleans, etc. 49 | # @option options [Object] :sort 50 | # Return matches sorted by either score or timestamp. 51 | # @option options [Object] :sort_dir 52 | # Change sort direction to ascending (asc) or descending (desc). 53 | # @option options [Object] :highlight 54 | # Pass a value of 1 to enable query highlight markers (see below). 55 | # @see https://api.slack.com/methods/search.messages 56 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/search/search.messages.json 57 | def search_messages(options = {}) 58 | throw ArgumentError.new('Required arguments :query missing') if options[:query].nil? 59 | post('search.messages', options) 60 | end 61 | end 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /lib/slack/real_time/concurrency/celluloid.rb: -------------------------------------------------------------------------------- 1 | require 'websocket/driver' 2 | require 'socket' 3 | require 'forwardable' 4 | require 'celluloid/current' 5 | require 'celluloid/io' 6 | 7 | module Slack 8 | module RealTime 9 | module Concurrency 10 | module Celluloid 11 | class Socket < Slack::RealTime::Socket 12 | include ::Celluloid::IO 13 | include ::Celluloid::Internals::Logger 14 | 15 | BLOCK_SIZE = 4096 16 | 17 | extend ::Forwardable 18 | def_delegator :socket, :write 19 | def_delegators :driver, :text, :binary, :close 20 | 21 | attr_reader :socket 22 | 23 | def initialize(*args) 24 | super 25 | end 26 | 27 | def connect! 28 | super 29 | run_loop 30 | end 31 | 32 | def run_loop 33 | @closing = false 34 | @socket = build_socket 35 | @connected = @socket.connect 36 | driver.start 37 | loop { read } if socket 38 | rescue EOFError => e 39 | logger.debug("#{self.class}##{__method__}") { e } 40 | driver.emit(:close, WebSocket::Driver::CloseEvent.new(1001, 'server closed connection')) unless @closing 41 | ensure 42 | current_actor.terminate if current_actor.alive? 43 | end 44 | 45 | def close 46 | @closing = true 47 | driver.close 48 | super 49 | end 50 | 51 | def read 52 | buffer = socket.readpartial(BLOCK_SIZE) 53 | async.handle_read(buffer) 54 | end 55 | 56 | def handle_read(buffer) 57 | logger.debug("#{self.class}##{__method__}") { buffer } 58 | driver.parse buffer 59 | end 60 | 61 | def write(data) 62 | logger.debug("#{self.class}##{__method__}") { data } 63 | socket.write(data) 64 | end 65 | 66 | def start_async(client) 67 | @client = client 68 | Actor.new(future.run_client_loop) 69 | end 70 | 71 | def run_client_loop 72 | @client.run_loop 73 | end 74 | 75 | def connected? 76 | !@connected.nil? 77 | end 78 | 79 | protected 80 | 81 | class Actor 82 | attr_reader :future 83 | 84 | def initialize(future) 85 | @future = future 86 | end 87 | 88 | def join 89 | @future.value 90 | end 91 | end 92 | 93 | def build_socket 94 | socket = TCPSocket.new(addr, port) 95 | socket = SSLSocket.new(socket, build_ssl_context) if secure? 96 | socket 97 | end 98 | 99 | def build_ssl_context 100 | OpenSSL::SSL::SSLContext.new(:TLSv1_2_client) 101 | end 102 | 103 | def build_driver 104 | ::WebSocket::Driver.client(self) 105 | end 106 | 107 | def connect 108 | @driver = build_driver 109 | end 110 | end 111 | end 112 | end 113 | end 114 | end 115 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/files_comments.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module FilesComments 8 | # 9 | # Add a comment to an existing file. 10 | # 11 | # @option options [file] :file 12 | # File to add a comment to. 13 | # @option options [Object] :comment 14 | # Text of the comment to add. 15 | # @option options [channel] :channel 16 | # Channel id (encoded) of which location to associate with the new comment. 17 | # @see https://api.slack.com/methods/files.comments.add 18 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/files.comments/files.comments.add.json 19 | def files_comments_add(options = {}) 20 | throw ArgumentError.new('Required arguments :file missing') if options[:file].nil? 21 | throw ArgumentError.new('Required arguments :comment missing') if options[:comment].nil? 22 | options = options.merge(channel: channels_id(options)['channel']['id']) if options[:channel] 23 | post('files.comments.add', options) 24 | end 25 | 26 | # 27 | # Delete an existing comment on a file. Only the original author of the comment or a Team Administrator may delete a file comment. 28 | # 29 | # @option options [file] :file 30 | # File to delete a comment from. 31 | # @option options [Object] :id 32 | # The comment to delete. 33 | # @see https://api.slack.com/methods/files.comments.delete 34 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/files.comments/files.comments.delete.json 35 | def files_comments_delete(options = {}) 36 | throw ArgumentError.new('Required arguments :file missing') if options[:file].nil? 37 | throw ArgumentError.new('Required arguments :id missing') if options[:id].nil? 38 | post('files.comments.delete', options) 39 | end 40 | 41 | # 42 | # Edit an existing comment on a file. Only the user who created a comment may make edits. Teams may configure a limited time window during which file comment edits are allowed. 43 | # 44 | # @option options [file] :file 45 | # File containing the comment to edit. 46 | # @option options [Object] :id 47 | # The comment to edit. 48 | # @option options [Object] :comment 49 | # Text of the comment to edit. 50 | # @see https://api.slack.com/methods/files.comments.edit 51 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/files.comments/files.comments.edit.json 52 | def files_comments_edit(options = {}) 53 | throw ArgumentError.new('Required arguments :file missing') if options[:file].nil? 54 | throw ArgumentError.new('Required arguments :id missing') if options[:id].nil? 55 | throw ArgumentError.new('Required arguments :comment missing') if options[:comment].nil? 56 | post('files.comments.edit', options) 57 | end 58 | end 59 | end 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/slack/web/api/endpoints/custom_specs/chat_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe Slack::Web::Api::Endpoints::Chat do 4 | let(:client) { Slack::Web::Client.new } 5 | context 'chat_postMessage' do 6 | it 'automatically converts attachments into JSON' do 7 | expect(client).to receive(:post).with( 8 | 'chat.postMessage', 9 | channel: 'channel', 10 | text: 'text', 11 | attachments: '[]' 12 | ) 13 | client.chat_postMessage(channel: 'channel', text: 'text', attachments: []) 14 | end 15 | context 'text and attachment arguments' do 16 | it 'requires text or attachments' do 17 | expect { client.chat_postMessage(channel: 'channel') }.to raise_error ArgumentError, /Required arguments :text or :attachments missing/ 18 | end 19 | it 'only text' do 20 | expect(client).to receive(:post).with('chat.postMessage', hash_including(text: 'text')) 21 | expect { client.chat_postMessage(channel: 'channel', text: 'text') }.to_not raise_error 22 | end 23 | it 'only attachments' do 24 | expect(client).to receive(:post).with('chat.postMessage', hash_including(attachments: '[]')) 25 | expect { client.chat_postMessage(channel: 'channel', attachments: []) }.to_not raise_error 26 | end 27 | it 'both text and attachments' do 28 | expect(client).to receive(:post).with('chat.postMessage', hash_including(text: 'text', attachments: '[]')) 29 | expect { client.chat_postMessage(channel: 'channel', text: 'text', attachments: []) }.to_not raise_error 30 | end 31 | end 32 | end 33 | 34 | context 'chat_update' do 35 | let(:ts) { '1405894322.002768' } 36 | it 'automatically converts attachments into JSON' do 37 | expect(client).to receive(:post).with( 38 | 'chat.update', 39 | attachments: '[]', 40 | channel: 'channel', 41 | text: 'text', 42 | ts: ts 43 | ) 44 | client.chat_update(attachments: [], channel: 'channel', text: 'text', ts: ts) 45 | end 46 | context 'ts arguments' do 47 | it 'requires ts' do 48 | expect { client.chat_update(channel: 'channel') }.to raise_error ArgumentError, /Required arguments :ts missing>/ 49 | end 50 | end 51 | context 'text and attachment arguments' do 52 | it 'requires text or attachments' do 53 | expect { client.chat_update(channel: 'channel', ts: ts) }.to raise_error ArgumentError, /Required arguments :text or :attachments missing/ 54 | end 55 | it 'only text' do 56 | expect(client).to receive(:post).with('chat.update', hash_including(text: 'text')) 57 | expect { client.chat_update(channel: 'channel', text: 'text', ts: ts) }.to_not raise_error 58 | end 59 | it 'only attachments' do 60 | expect(client).to receive(:post).with('chat.update', hash_including(attachments: '[]')) 61 | expect { client.chat_update(attachments: [], channel: 'channel', ts: ts) }.to_not raise_error 62 | end 63 | it 'both text and attachments' do 64 | expect(client).to receive(:post).with('chat.update', hash_including(text: 'text', attachments: '[]')) 65 | expect { client.chat_update(attachments: [], channel: 'channel', text: 'text', ts: ts) }.to_not raise_error 66 | end 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /bin/commands/reactions.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Reactions methods.' 4 | command 'reactions' do |g| 5 | g.desc 'This method adds a reaction (emoji) to an item (file, file comment, channel message, group message, or direct message).' 6 | g.long_desc %( This method adds a reaction (emoji) to an item (file, file comment, channel message, group message, or direct message). One of file, file_comment, or the combination of channel and timestamp must be specified. ) 7 | g.command 'add' do |c| 8 | c.flag 'name', desc: 'Reaction (emoji) name.' 9 | c.flag 'file', desc: 'File to add reaction to.' 10 | c.flag 'file_comment', desc: 'File comment to add reaction to.' 11 | c.flag 'channel', desc: 'Channel where the message to add reaction to was posted.' 12 | c.flag 'timestamp', desc: 'Timestamp of the message to add reaction to.' 13 | c.action do |_global_options, options, _args| 14 | puts JSON.dump($client.reactions_add(options)) 15 | end 16 | end 17 | 18 | g.desc 'This method returns a list of all reactions for a single item (file, file comment, channel message, group message, or direct message).' 19 | g.long_desc %( This method returns a list of all reactions for a single item (file, file comment, channel message, group message, or direct message). ) 20 | g.command 'get' do |c| 21 | c.flag 'file', desc: 'File to get reactions for.' 22 | c.flag 'file_comment', desc: 'File comment to get reactions for.' 23 | c.flag 'channel', desc: 'Channel where the message to get reactions for was posted.' 24 | c.flag 'timestamp', desc: 'Timestamp of the message to get reactions for.' 25 | c.flag 'full', desc: 'If true always return the complete reaction list.' 26 | c.action do |_global_options, options, _args| 27 | puts JSON.dump($client.reactions_get(options)) 28 | end 29 | end 30 | 31 | g.desc 'This method returns a list of all items (file, file comment, channel message, group message, or direct message) reacted to by a user.' 32 | g.long_desc %( This method returns a list of all items (file, file comment, channel message, group message, or direct message) reacted to by a user. ) 33 | g.command 'list' do |c| 34 | c.flag 'user', desc: 'Show reactions made by this user. Defaults to the authed user.' 35 | c.flag 'full', desc: 'If true always return the complete reaction list.' 36 | c.action do |_global_options, options, _args| 37 | puts JSON.dump($client.reactions_list(options)) 38 | end 39 | end 40 | 41 | g.desc 'This method removes a reaction (emoji) from an item (file, file comment, channel message, group message, or direct message).' 42 | g.long_desc %( This method removes a reaction (emoji) from an item (file, file comment, channel message, group message, or direct message). One of file, file_comment, or the combination of channel and timestamp must be specified. ) 43 | g.command 'remove' do |c| 44 | c.flag 'name', desc: 'Reaction (emoji) name.' 45 | c.flag 'file', desc: 'File to remove reaction from.' 46 | c.flag 'file_comment', desc: 'File comment to remove reaction from.' 47 | c.flag 'channel', desc: 'Channel where the message to remove reaction from was posted.' 48 | c.flag 'timestamp', desc: 'Timestamp of the message to remove reaction from.' 49 | c.action do |_global_options, options, _args| 50 | puts JSON.dump($client.reactions_remove(options)) 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /bin/commands/usergroups.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc "Get info on your team's User Groups." 4 | command 'usergroups' do |g| 5 | g.desc 'This method is used to create a User Group.' 6 | g.long_desc %( This method is used to create a User Group. ) 7 | g.command 'create' do |c| 8 | c.flag 'name', desc: 'A name for the User Group. Must be unique among User Groups.' 9 | c.flag 'handle', desc: 'A mention handle. Must be unique among channels, users and User Groups.' 10 | c.flag 'description', desc: 'A short description of the User Group.' 11 | c.flag 'channels', desc: 'A comma separated string of encoded channel IDs for which the User Group uses as a default.' 12 | c.flag 'include_count', desc: 'Include the number of users in each User Group.' 13 | c.action do |_global_options, options, _args| 14 | puts JSON.dump($client.usergroups_create(options)) 15 | end 16 | end 17 | 18 | g.desc 'This method disables an existing User Group.' 19 | g.long_desc %( This method disables an existing User Group. ) 20 | g.command 'disable' do |c| 21 | c.flag 'usergroup', desc: 'The encoded ID of the User Group to disable.' 22 | c.flag 'include_count', desc: 'Include the number of users in the User Group.' 23 | c.action do |_global_options, options, _args| 24 | puts JSON.dump($client.usergroups_disable(options)) 25 | end 26 | end 27 | 28 | g.desc 'This method enables a User Group which was previously disabled.' 29 | g.long_desc %( This method enables a User Group which was previously disabled. ) 30 | g.command 'enable' do |c| 31 | c.flag 'usergroup', desc: 'The encoded ID of the User Group to enable.' 32 | c.flag 'include_count', desc: 'Include the number of users in the User Group.' 33 | c.action do |_global_options, options, _args| 34 | puts JSON.dump($client.usergroups_enable(options)) 35 | end 36 | end 37 | 38 | g.desc 'This method returns a list of all User Groups in the team. This can optionally include disabled User Groups.' 39 | g.long_desc %( This method returns a list of all User Groups in the team. This can optionally include disabled User Groups. ) 40 | g.command 'list' do |c| 41 | c.flag 'include_disabled', desc: 'Include disabled User Groups.' 42 | c.flag 'include_count', desc: 'Include the number of users in each User Group.' 43 | c.flag 'include_users', desc: 'Include the list of users for each User Group.' 44 | c.action do |_global_options, options, _args| 45 | puts JSON.dump($client.usergroups_list(options)) 46 | end 47 | end 48 | 49 | g.desc 'This method updates the properties of an existing User Group.' 50 | g.long_desc %( This method updates the properties of an existing User Group. ) 51 | g.command 'update' do |c| 52 | c.flag 'usergroup', desc: 'The encoded ID of the User Group to update.' 53 | c.flag 'name', desc: 'A name for the User Group. Must be unique among User Groups.' 54 | c.flag 'handle', desc: 'A mention handle. Must be unique among channels, users and User Groups.' 55 | c.flag 'description', desc: 'A short description of the User Group.' 56 | c.flag 'channels', desc: 'A comma separated string of encoded channel IDs for which the User Group uses as a default.' 57 | c.flag 'include_count', desc: 'Include the number of users in the User Group.' 58 | c.action do |_global_options, options, _args| 59 | puts JSON.dump($client.usergroups_update(options)) 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/tasks/web.rake: -------------------------------------------------------------------------------- 1 | # largely from https://github.com/aki017/slack-ruby-gem 2 | require 'json-schema' 3 | require 'erubis' 4 | require 'active_support' 5 | require 'active_support/core_ext' 6 | 7 | namespace :slack do 8 | namespace :web do 9 | namespace :api do 10 | desc 'Update API.' 11 | task update: [:git_update] do 12 | group_schema = JSON.parse(File.read('lib/slack/web/api/schema/group.json')) 13 | groups = Dir.glob('lib/slack/web/api/slack-api-ref/groups/**/*.json').each_with_object({}) do |path, result| 14 | name = File.basename(path, '.json') 15 | parsed = JSON.parse(File.read(path)) 16 | JSON::Validator.validate(group_schema, parsed, insert_defaults: true) 17 | result[name] = parsed 18 | end 19 | 20 | method_schema = JSON.parse(File.read('lib/slack/web/api/schema/method.json')) 21 | data = [ 22 | Dir.glob('lib/slack/web/api/slack-api-ref/methods/**/*.json'), 23 | Dir.glob('lib/slack/web/api/mixins/**/*.json') 24 | ].flatten.each_with_object({}) do |path, result| 25 | file_name = File.basename(path, '.json') 26 | prefix = file_name.split('.')[0..-2].join('.') 27 | name = file_name.split('.')[-1] 28 | result[prefix] ||= {} 29 | parsed = JSON.parse(File.read(path)) 30 | JSON::Validator.validate(method_schema, parsed, insert_defaults: true) 31 | result[prefix][name] = parsed 32 | end 33 | 34 | method_template = Erubis::Eruby.new(File.read('lib/slack/web/api/templates/method.erb')) 35 | method_spec_template = Erubis::Eruby.new(File.read('lib/slack/web/api/templates/method_spec.erb')) 36 | command_template = Erubis::Eruby.new(File.read('lib/slack/web/api/templates/command.erb')) 37 | data.each_with_index do |(group, names), index| 38 | printf "%2d/%2d %10s %s\n", index, data.size, group, names.keys 39 | # method 40 | snaked_group = group.tr('.', '_') 41 | rendered_method = method_template.result(group: group, names: names) 42 | File.write "lib/slack/web/api/endpoints/#{snaked_group}.rb", rendered_method 43 | custom_spec_exists = File.exist?("spec/slack/web/api/endpoints/custom_specs/#{group}_spec.rb") 44 | unless custom_spec_exists 45 | rendered_method_spec = method_spec_template.result(group: group, names: names) 46 | File.write "spec/slack/web/api/endpoints/#{snaked_group}_spec.rb", rendered_method_spec 47 | end 48 | Dir.glob("lib/slack/web/api/patches/#{group}*.patch").sort.each do |patch| 49 | puts "- patching #{patch}" 50 | system("git apply #{patch}") || fail('failed to apply patch') 51 | end 52 | # command 53 | rendered_command = command_template.result(group: groups[group], names: names) 54 | File.write "bin/commands/#{snaked_group}.rb", rendered_command 55 | end 56 | 57 | endpoints_template = Erubis::Eruby.new(File.read('lib/slack/web/api/templates/endpoints.erb')) 58 | File.write 'lib/slack/web/api/endpoints.rb', endpoints_template.result(files: data.keys.map { |key| key.tr('.', '_') }) 59 | 60 | commands_template = Erubis::Eruby.new(File.read('lib/slack/web/api/templates/commands.erb')) 61 | File.write 'bin/commands.rb', commands_template.result(files: data.keys.map { |key| key.tr('.', '_') }) 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /bin/commands/users.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Get info on members of your Slack team.' 4 | command 'users' do |g| 5 | g.desc "This method lets you find out information about a user's presence." 6 | g.long_desc %( This method lets you find out information about a user's presence. Consult the presence documentation for more details. ) 7 | g.command 'getPresence' do |c| 8 | c.flag 'user', desc: 'User to get presence info on. Defaults to the authed user.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.users_getPresence(options)) 11 | end 12 | end 13 | 14 | g.desc "After your Slack app is awarded an identity token through Sign in with Slack, use this method to retrieve a user's identity." 15 | g.long_desc %( After your Slack app is awarded an identity token through Sign in with Slack, use this method to retrieve a user's identity. ) 16 | g.command 'identity' do |c| 17 | c.action do |_global_options, options, _args| 18 | puts JSON.dump($client.users_identity(options)) 19 | end 20 | end 21 | 22 | g.desc 'This method returns information about a team member.' 23 | g.long_desc %( This method returns information about a team member. ) 24 | g.command 'info' do |c| 25 | c.flag 'user', desc: 'User to get info on.' 26 | c.action do |_global_options, options, _args| 27 | puts JSON.dump($client.users_info(options)) 28 | end 29 | end 30 | 31 | g.desc 'This method returns a list of all users in the team. This includes deleted/deactivated users.' 32 | g.long_desc %( This method returns a list of all users in the team. This includes deleted/deactivated users. ) 33 | g.command 'list' do |c| 34 | c.flag 'presence', desc: 'Whether to include presence data in the output.' 35 | c.action do |_global_options, options, _args| 36 | puts JSON.dump($client.users_list(options)) 37 | end 38 | end 39 | 40 | g.desc 'This method lets the slack messaging server know that the authenticated user' 41 | g.long_desc %( This method lets the slack messaging server know that the authenticated user is currently active. Consult the presence documentation for more details. ) 42 | g.command 'setActive' do |c| 43 | c.action do |_global_options, options, _args| 44 | puts JSON.dump($client.users_setActive(options)) 45 | end 46 | end 47 | 48 | g.desc "This method lets you set the calling user's manual presence." 49 | g.long_desc %( This method lets you set the calling user's manual presence. Consult the presence documentation for more details. ) 50 | g.command 'setPresence' do |c| 51 | c.flag 'presence', desc: 'Either auto or away.' 52 | c.action do |_global_options, options, _args| 53 | puts JSON.dump($client.users_setPresence(options)) 54 | end 55 | end 56 | 57 | g.desc 'This method returns the ID of a team user.' 58 | g.long_desc %( This method returns the ID of a team user. ) 59 | g.command 'id' do |c| 60 | c.flag 'user', desc: 'User to get ID for, prefixed with @.' 61 | c.action do |_global_options, options, _args| 62 | puts JSON.dump($client.users_id(options)) 63 | end 64 | end 65 | 66 | g.desc 'This method searches for users.' 67 | g.long_desc %( This method searches for users. ) 68 | g.command 'search' do |c| 69 | c.flag 'user', desc: 'User to search for.' 70 | c.action do |_global_options, options, _args| 71 | puts JSON.dump($client.users_search(options)) 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /lib/slack/web/api/endpoints/reminders.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | module Slack 4 | module Web 5 | module Api 6 | module Endpoints 7 | module Reminders 8 | # 9 | # This method creates a reminder. 10 | # 11 | # @option options [Object] :text 12 | # The content of the reminder. 13 | # @option options [Object] :time 14 | # When this reminder should happen: the Unix timestamp (up to five years from now), the number of seconds until the reminder (if within 24 hours), or a natural language description (Ex. "in 15 minutes," or "every Thursday"). 15 | # @option options [user] :user 16 | # The user who will receive the reminder. If no user is specified, the reminder will go to user who created it. 17 | # @see https://api.slack.com/methods/reminders.add 18 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/reminders/reminders.add.json 19 | def reminders_add(options = {}) 20 | throw ArgumentError.new('Required arguments :text missing') if options[:text].nil? 21 | throw ArgumentError.new('Required arguments :time missing') if options[:time].nil? 22 | options = options.merge(user: users_id(options)['user']['id']) if options[:user] 23 | post('reminders.add', options) 24 | end 25 | 26 | # 27 | # This method completes a reminder. 28 | # 29 | # @option options [Object] :reminder 30 | # The ID of the reminder to be marked as complete. 31 | # @see https://api.slack.com/methods/reminders.complete 32 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/reminders/reminders.complete.json 33 | def reminders_complete(options = {}) 34 | throw ArgumentError.new('Required arguments :reminder missing') if options[:reminder].nil? 35 | post('reminders.complete', options) 36 | end 37 | 38 | # 39 | # This method deletes a reminder. 40 | # 41 | # @option options [Object] :reminder 42 | # The ID of the reminder. 43 | # @see https://api.slack.com/methods/reminders.delete 44 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/reminders/reminders.delete.json 45 | def reminders_delete(options = {}) 46 | throw ArgumentError.new('Required arguments :reminder missing') if options[:reminder].nil? 47 | post('reminders.delete', options) 48 | end 49 | 50 | # 51 | # This method returns information about a reminder. 52 | # 53 | # @option options [Object] :reminder 54 | # The ID of the reminder. 55 | # @see https://api.slack.com/methods/reminders.info 56 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/reminders/reminders.info.json 57 | def reminders_info(options = {}) 58 | throw ArgumentError.new('Required arguments :reminder missing') if options[:reminder].nil? 59 | post('reminders.info', options) 60 | end 61 | 62 | # 63 | # This method lists all reminders created by or for a given user. 64 | # 65 | # @see https://api.slack.com/methods/reminders.list 66 | # @see https://github.com/dblock/slack-api-ref/blob/master/methods/reminders/reminders.list.json 67 | def reminders_list(options = {}) 68 | post('reminders.list', options) 69 | end 70 | end 71 | end 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /bin/commands/files.rb: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by lib/tasks/web.rake 2 | 3 | desc 'Get info on files uploaded to Slack, upload new files to Slack.' 4 | command 'files' do |g| 5 | g.desc 'This method deletes a file from your team.' 6 | g.long_desc %( This method deletes a file from your team. ) 7 | g.command 'delete' do |c| 8 | c.flag 'file', desc: 'ID of file to delete.' 9 | c.action do |_global_options, options, _args| 10 | puts JSON.dump($client.files_delete(options)) 11 | end 12 | end 13 | 14 | g.desc 'This method returns information about a file in your team.' 15 | g.long_desc %( This method returns information about a file in your team. ) 16 | g.command 'info' do |c| 17 | c.flag 'file', desc: 'Specify a file by providing its ID.' 18 | c.action do |_global_options, options, _args| 19 | puts JSON.dump($client.files_info(options)) 20 | end 21 | end 22 | 23 | g.desc 'This method returns a list of files within the team. It can be filtered and sliced in various ways.' 24 | g.long_desc %( This method returns a list of files within the team. It can be filtered and sliced in various ways. ) 25 | g.command 'list' do |c| 26 | c.flag 'user', desc: 'Filter files created by a single user.' 27 | c.flag 'channel', desc: 'Filter files appearing in a specific channel, indicated by its ID.' 28 | c.flag 'ts_from', desc: 'Filter files created after this timestamp (inclusive).' 29 | c.flag 'ts_to', desc: 'Filter files created before this timestamp (inclusive).' 30 | c.flag 'types', desc: 'Filter files by type: 31 | 32 | all - All files 33 | spaces - Posts 34 | snippets - Snippets 35 | images - Image files 36 | gdocs - Google docs 37 | zips - Zip files 38 | pdfs - PDF files 39 | 40 | 41 | You can pass multiple values in the types argument, like types=spaces,snippets.The default value is all, which does not filter the list. 42 | .' 43 | c.action do |_global_options, options, _args| 44 | puts JSON.dump($client.files_list(options)) 45 | end 46 | end 47 | 48 | g.desc 'This method disables public/external sharing for a file.' 49 | g.long_desc %( This method disables public/external sharing for a file. ) 50 | g.command 'revokePublicURL' do |c| 51 | c.flag 'file', desc: 'File to revoke.' 52 | c.action do |_global_options, options, _args| 53 | puts JSON.dump($client.files_revokePublicURL(options)) 54 | end 55 | end 56 | 57 | g.desc 'This method enables public/external sharing for a file.' 58 | g.long_desc %( This method enables public/external sharing for a file. ) 59 | g.command 'sharedPublicURL' do |c| 60 | c.flag 'file', desc: 'File to share.' 61 | c.action do |_global_options, options, _args| 62 | puts JSON.dump($client.files_sharedPublicURL(options)) 63 | end 64 | end 65 | 66 | g.desc 'This method allows you to create or upload an existing file.' 67 | g.long_desc %( This method allows you to create or upload an existing file. ) 68 | g.command 'upload' do |c| 69 | c.flag 'file', desc: 'File contents via multipart/form-data. If omitting this parameter, you must submit content.' 70 | c.flag 'content', desc: 'File contents via a POST variable. If omitting this parameter, you must provide a file.' 71 | c.flag 'filetype', desc: 'A file type identifier.' 72 | c.flag 'filename', desc: 'Filename of file.' 73 | c.flag 'title', desc: 'Title of file.' 74 | c.flag 'initial_comment', desc: 'Initial comment to add to file.' 75 | c.flag 'channels', desc: 'Comma-separated list of channel names or IDs where the file will be shared.' 76 | c.action do |_global_options, options, _args| 77 | puts JSON.dump($client.files_upload(options)) 78 | end 79 | end 80 | end 81 | --------------------------------------------------------------------------------