├── .github
└── workflows
│ └── gem-push.yml
├── .gitignore
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── bin
└── console
├── breacan.gemspec
└── lib
├── breacan.rb
└── breacan
├── authentication.rb
├── client.rb
├── client
├── api.rb
├── auth.rb
├── channels.rb
├── chat.rb
├── emoji.rb
├── files.rb
├── groups.rb
├── im.rb
├── oauth.rb
├── rtm.rb
├── search.rb
├── star.rb
├── usergroups.rb
└── users.rb
├── configurable.rb
├── error.rb
├── response
└── custom.rb
└── version.rb
/.github/workflows/gem-push.yml:
--------------------------------------------------------------------------------
1 | name: Ruby Gem
2 |
3 | on:
4 | push:
5 | branches: [ "master" ]
6 |
7 | jobs:
8 | build:
9 | name: Build + Publish
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: read
13 | packages: write
14 |
15 | steps:
16 | - uses: actions/checkout@v3
17 | - name: Set up Ruby
18 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
19 | # change this to (see https://github.com/ruby/setup-ruby#versioning):
20 | # uses: ruby/setup-ruby@v1
21 | uses: ruby/setup-ruby@55283cc23133118229fd3f97f9336ee23a179fcf # v1.146.0
22 | with:
23 | ruby-version: 3
24 |
25 | - name: Publish to GPR
26 | id: gpr
27 | run: |
28 | mkdir -p $HOME/.gem
29 | touch $HOME/.gem/credentials
30 | chmod 0600 $HOME/.gem/credentials
31 | printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
32 | gem build *.gemspec
33 | VERSION=$(gem spec *.gem version | grep version | awk '{print $2}')
34 | EXISTS=$(gem search ^breacan$ -a | grep -c $VERSION)
35 | if [ $EXISTS -eq 0 ]; then
36 | gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
37 | else
38 | echo "Gem with the same version already exists. Skipping push..."
39 | echo "skip_publish_to_rubygems=true" >> $GITHUB_OUTPUT
40 | fi
41 | env:
42 | GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
43 | OWNER: ${{ github.repository_owner }}
44 |
45 | - name: Publish to RubyGems
46 | if: ${{ steps.gpr.outputs.skip_publish_to_rubygems != 'true' }}
47 | run: |
48 | mkdir -p $HOME/.gem
49 | touch $HOME/.gem/credentials
50 | chmod 0600 $HOME/.gem/credentials
51 | printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
52 | gem build *.gemspec
53 | gem push *.gem
54 | env:
55 | GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
56 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.bundle/
2 | /.yardoc
3 | /Gemfile.lock
4 | /_yardoc/
5 | /coverage/
6 | /doc/
7 | /pkg/
8 | /spec/reports/
9 | /tmp/
10 | *.bundle
11 | *.so
12 | *.o
13 | *.a
14 | mkmf.log
15 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | # Specify your gem's dependencies in breacan.gemspec
4 | gemspec
5 |
6 | gem 'pry'
7 | gem 'awesome_print'
8 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015 linyows
2 |
3 | MIT License
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Breacan: Simple Ruby wrapper for Slack API.
4 |
5 |
6 |
7 |
8 |
9 | Installation
10 | ------------
11 |
12 | Add this line to your application's Gemfile:
13 |
14 | ```ruby
15 | gem 'breacan'
16 | ```
17 |
18 | And then execute:
19 |
20 | $ bundle
21 |
22 | Or install it yourself as:
23 |
24 | $ gem install breacan
25 |
26 | Usage
27 | -----
28 |
29 | example:
30 |
31 | ```ruby
32 | require 'breacan'
33 | Breacan.access_token = 'xoxp-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
34 | Breacan.channels
35 | => [{:id=>"C03QXXXX",
36 | :name=>"hello",
37 | :is_channel=>true,
38 | :created=>1424735886,
39 | :creator=>"U03PXXXX",
40 | :is_archived=>false,
41 | :is_general=>false,
42 | :is_member=>false,
43 | :members=> ["U0NLXXXX",...
44 | Breacan.channel_by_name('hello').id
45 | => "C03QXXXX"
46 | ```
47 |
48 | Contributing
49 | ------------
50 |
51 | 1. Fork it ( https://github.com/linyows/breacan/fork )
52 | 2. Create your feature branch (`git checkout -b my-new-feature`)
53 | 3. Commit your changes (`git commit -am 'Add some feature'`)
54 | 4. Push to the branch (`git push origin my-new-feature`)
55 | 5. Create a new Pull Request
56 |
57 | Authors
58 | -------
59 |
60 | - [linyows](https://github.com/linyows)
61 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/gem_tasks"
2 |
3 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require "bundler/setup"
4 | require "breacan"
5 |
6 | # You can add fixtures and/or initialization code here to make experimenting
7 | # with your gem easier. You can also use a different console, if you like.
8 |
9 | # (If you use this, don't forget to add pry to your Gemfile!)
10 | # require "pry"
11 | # Pry.start
12 |
13 | require "pry"
14 | Pry.start
15 |
--------------------------------------------------------------------------------
/breacan.gemspec:
--------------------------------------------------------------------------------
1 | # coding: utf-8
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 | require 'breacan/version'
5 |
6 | Gem::Specification.new do |spec|
7 | spec.name = "breacan"
8 | spec.version = Breacan::VERSION
9 | spec.authors = ["linyows"]
10 | spec.email = ["linyows@gmail.com"]
11 | spec.summary = %q{Simple Ruby wrapper for Slack API.}
12 | spec.description = %q{Simple Ruby wrapper for Slack API.}
13 | spec.homepage = "https://github.com/linyows/breacan"
14 | spec.license = "MIT"
15 |
16 | spec.files = `git ls-files -z`.split("\x0")
17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19 | spec.require_paths = ["lib"]
20 |
21 | spec.add_dependency "sawyer", "~> 0.6"
22 | spec.add_dependency "activesupport"
23 | spec.add_development_dependency "bundler", "~> 1.7"
24 | spec.add_development_dependency "rake", "~> 10.0"
25 |
26 | end
27 |
--------------------------------------------------------------------------------
/lib/breacan.rb:
--------------------------------------------------------------------------------
1 | require 'breacan/version'
2 | require 'breacan/client'
3 |
4 | module Breacan
5 | class << self
6 | include Breacan::Configurable
7 |
8 | def client
9 | unless defined?(@client) && @client.same_options?(options)
10 | @client = Breacan::Client.new(options)
11 | end
12 | @client
13 | end
14 |
15 | private
16 |
17 | def method_missing(method_name, *args, &block)
18 | return super unless client.respond_to?(method_name)
19 | client.send(method_name, *args, &block)
20 | end
21 | end
22 | end
23 |
24 | Breacan.setup
25 |
--------------------------------------------------------------------------------
/lib/breacan/authentication.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | module Authentication
3 | def token_authenticated?
4 | !!@access_token
5 | end
6 | end
7 | end
8 |
--------------------------------------------------------------------------------
/lib/breacan/client.rb:
--------------------------------------------------------------------------------
1 | require 'sawyer'
2 | require 'active_support'
3 | require 'active_support/core_ext/hash'
4 | require 'breacan/configurable'
5 | require 'breacan/authentication'
6 | require 'breacan/client/api'
7 | require 'breacan/client/auth'
8 | require 'breacan/client/channels'
9 | require 'breacan/client/chat'
10 | require 'breacan/client/emoji'
11 | require 'breacan/client/files'
12 | require 'breacan/client/groups'
13 | require 'breacan/client/im'
14 | require 'breacan/client/oauth'
15 | require 'breacan/client/rtm'
16 | require 'breacan/client/search'
17 | require 'breacan/client/star'
18 | require 'breacan/client/users'
19 | require 'breacan/client/usergroups'
20 |
21 | module Breacan
22 | class Client
23 | include Breacan::Authentication
24 | include Breacan::Configurable
25 | include Breacan::Client::Api
26 | include Breacan::Client::Auth
27 | include Breacan::Client::Channels
28 | include Breacan::Client::Chat
29 | include Breacan::Client::Emoji
30 | include Breacan::Client::Files
31 | include Breacan::Client::Groups
32 | include Breacan::Client::Im
33 | include Breacan::Client::OAuth
34 | include Breacan::Client::Rtm
35 | include Breacan::Client::Search
36 | include Breacan::Client::Star
37 | include Breacan::Client::Users
38 | include Breacan::Client::Usergroups
39 |
40 | CONVENIENCE_HEADERS = Set.new(%i(accept content_type))
41 |
42 | def initialize(options = {})
43 | Breacan::Configurable.keys.each do |key|
44 | instance_variable_set(:"@#{key}", options[key] || Breacan.instance_variable_get(:"@#{key}"))
45 | end
46 | end
47 |
48 | def same_options?(opts)
49 | opts.hash == options.hash
50 | end
51 |
52 | def get(url, options = {})
53 | return get_with_auto_paginate(url, options) if auto_paginate
54 | request :get, url, parse_query_and_convenience_headers(options)
55 | end
56 |
57 | def get_with_auto_paginate(url, options = {})
58 | res = nil
59 | if url.end_with?('.list')
60 | nextc = nil
61 | loop do
62 | r = request :get, url, parse_query_and_convenience_headers(options.merge({cursor: nextc}))
63 | if r.is_a?(Sawyer::Resource)
64 | res ||= {}
65 | res = res.deep_merge(r) do |key, this_val, other_val|
66 | if this_val.is_a?(Array) && other_val.is_a?(Array)
67 | this_val + other_val
68 | else
69 | other_val
70 | end
71 | end
72 | elsif r.is_a?(Array)
73 | res ||= []
74 | res.concat(r)
75 | else
76 | raise "unknown response type"
77 | end
78 |
79 | if r.respond_to?(:response_metadata)
80 | if r.response_metadata.next_cursor == ""
81 | res = Sawyer::Resource.new(Sawyer::Agent.new(api_endpoint), res)
82 | break
83 | end
84 | nextc = r.response_metadata.next_cursor
85 | else
86 | break
87 | end
88 | end
89 | else
90 | res = request :get, url, parse_query_and_convenience_headers(options)
91 | end
92 | res
93 | end
94 |
95 | def post(url, options = {})
96 | request :post, url, options
97 | end
98 |
99 | def put(url, options = {})
100 | request :put, url, options
101 | end
102 |
103 | def patch(url, options = {})
104 | request :patch, url, options
105 | end
106 |
107 | def delete(url, options = {})
108 | request :delete, url, options
109 | end
110 |
111 | def head(url, options = {})
112 | request :head, url, parse_query_and_convenience_headers(options)
113 | end
114 |
115 | def agent
116 | @agent ||= Sawyer::Agent.new(api_endpoint, sawyer_options) do |http|
117 | http.headers[:accept] = media_type
118 | http.headers[:user_agent] = user_agent
119 | end
120 | end
121 |
122 | private
123 |
124 | def request(method, path, data, options = {})
125 | if data.is_a?(Hash)
126 | options[:query] = data.delete(:query) || {}
127 | options[:headers] = data.delete(:headers) || {}
128 | if accept = data.delete(:accept)
129 | options[:headers][:accept] = accept
130 | end
131 | options[:query][:token] = access_token
132 | end
133 |
134 | @last_response = response = agent.call(
135 | method,
136 | URI::Parser.new.escape(path.to_s),
137 | data,
138 | options
139 | )
140 |
141 | simplize_body response.data
142 | end
143 |
144 | def simplize_body(body)
145 | keys = body.to_hash.keys.dup
146 |
147 | @cache_ts = if keys.include?(:cache_ts)
148 | keys.delete(:cache_ts)
149 | body.cache_ts
150 | else
151 | nil
152 | end
153 |
154 | keys.count == 1 ? body[keys.last] : body
155 | end
156 |
157 | def cache_ts
158 | @cache_ts if defined? @cache_ts
159 | end
160 |
161 | def last_response
162 | @last_response if defined? @last_response
163 | end
164 |
165 | def boolean_from_response(method, path, options = {})
166 | request(method, path, options)
167 | @last_response.status == 204
168 | rescue Breacan::NotFound
169 | false
170 | end
171 |
172 | def sawyer_options
173 | opts = {
174 | :links_parser => Sawyer::LinkParsers::Simple.new
175 | }
176 | conn_opts = @connection_options
177 | conn_opts[:builder] = @middleware if @middleware
178 | conn_opts[:proxy] = @proxy if @proxy
179 | opts[:faraday] = Faraday.new(conn_opts)
180 | opts[:serializer] = @serializer
181 |
182 | opts
183 | end
184 |
185 | def parse_query_and_convenience_headers(options)
186 | headers = options.fetch(:headers, {})
187 | CONVENIENCE_HEADERS.each do |h|
188 | if header = options.delete(h)
189 | headers[h] = header
190 | end
191 | end
192 | query = options.delete(:query)
193 | opts = {:query => options}
194 | opts[:query].merge!(query) if query && query.is_a?(Hash)
195 | opts[:headers] = headers unless headers.empty?
196 |
197 | opts
198 | end
199 | end
200 | end
201 |
--------------------------------------------------------------------------------
/lib/breacan/client/api.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Api
4 | def api_test(args)
5 | get 'api.test', query: args
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/breacan/client/auth.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Auth
4 | def auth_test(args)
5 | get 'auth.test', query: args
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/breacan/client/channels.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Channels
4 | def channels_archive(args)
5 | get 'channels.archive', query: args
6 | end
7 |
8 | def channels_create(args)
9 | get 'channels.create', query: args
10 | end
11 |
12 | def channels_history(args)
13 | get 'channels.history', query: args
14 | end
15 |
16 | def channels_info(id, options)
17 | get 'channels.info', query: { channel: id }.merge(options)
18 | end
19 | alias_method :channel, :channels_info
20 |
21 | def channels_invite(args)
22 | get 'channels.invite', query: args
23 | end
24 |
25 | def channels_join(args)
26 | get 'channels.join', query: args
27 | end
28 |
29 | def channels_kick(args)
30 | get 'channels.kick', query: args
31 | end
32 |
33 | def channels_leave(args)
34 | get 'channels.leave', query: args
35 | end
36 |
37 | def channels_list(args = nil)
38 | get 'channels.list', query: args
39 | end
40 | alias_method :channels, :channels_list
41 |
42 | def channels_mark(args)
43 | get 'channels.mark', query: args
44 | end
45 |
46 | def channels_rename(args)
47 | get 'channels.rename', query: args
48 | end
49 |
50 | def channels_set_purpose(args)
51 | get 'channels.setPurpose', query: args
52 | end
53 |
54 | def channels_set_topic(args)
55 | get 'channels.setTopic', query: args
56 | end
57 |
58 | def channels_unarchive(args)
59 | get 'channels.unarchive', query: args
60 | end
61 |
62 | def channel_by_name(name)
63 | channels.find { |ch| ch.name == name }
64 | end
65 | end
66 | end
67 | end
68 |
--------------------------------------------------------------------------------
/lib/breacan/client/chat.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Chat
4 | def chat_delete(args)
5 | get 'chat.delete', query: args
6 | end
7 |
8 | def chat_post_message(args)
9 | get 'chat.postMessage', query: args
10 | end
11 |
12 | def chat_update(args)
13 | get 'chat.update', query: args
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/breacan/client/emoji.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Emoji
4 | def emoji_list
5 | get 'emoji.list'
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/breacan/client/files.rb:
--------------------------------------------------------------------------------
1 |
2 | module Breacan
3 | class Client
4 | module Files
5 | def files_delete(args)
6 | get 'files.delete', query: args
7 | end
8 |
9 | def files_info(args)
10 | get 'files.info', query: args
11 | end
12 |
13 | def files_list(args)
14 | get 'files.list', query: args
15 | end
16 |
17 | def files_upload(args)
18 | set_files_upload_builder
19 | data = {}
20 | if args[:file]
21 | data[:file] = args[:file]
22 | args.delete(:file)
23 | end
24 | data[:query] = args
25 | res = post 'files.upload', data
26 | reset_files_upload_builder
27 | res
28 | end
29 |
30 | def set_files_upload_builder
31 | @serializer = Breacan::Client::Files::FileSerializer.any_json
32 | @middleware = Faraday::RackBuilder.new do |c|
33 | c.request :multipart
34 | c.request :url_encoded
35 | c.adapter :net_http
36 | c.response :breacan_custom
37 | end
38 | end
39 |
40 | def reset_files_upload_builder
41 | @middleware = default_builder
42 | end
43 |
44 | class FileSerializer < Sawyer::Serializer
45 | def encode(data)
46 | data
47 | end
48 | end
49 | end
50 | end
51 | end
52 |
--------------------------------------------------------------------------------
/lib/breacan/client/groups.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Groups
4 | def groups_archive(args)
5 | get 'groups.archive', query: args
6 | end
7 |
8 | def groups_create(args)
9 | get 'groups.create', query: args
10 | end
11 |
12 | def groups_history(args)
13 | get 'groups.history', query: args
14 | end
15 |
16 | def groups_info(args)
17 | get 'groups.info', query: args
18 | end
19 |
20 | def groups_invite(args)
21 | get 'groups.invite', query: args
22 | end
23 |
24 | def groups_join(args)
25 | get 'groups.join', query: args
26 | end
27 |
28 | def groups_kick(args)
29 | get 'groups.kick', query: args
30 | end
31 |
32 | def groups_leave(args)
33 | get 'groups.leave', query: args
34 | end
35 |
36 | def groups_list(args = nil)
37 | get 'groups.list', query: args
38 |
39 | end
40 |
41 | def groups_mark(args)
42 | get 'groups.mark', query: args
43 | end
44 |
45 | def groups_rename(args)
46 | get 'groups.rename', query: args
47 | end
48 |
49 | def groups_set_purpose(args)
50 | get 'groups.setPurpose', query: args
51 | end
52 |
53 | def groups_set_topic(args)
54 | get 'groups.setTopic', query: args
55 | end
56 |
57 | def groups_unarchive(args)
58 | get 'groups.unarchive', query: args
59 | end
60 |
61 | def groups_info_by_name(name)
62 | groups_list.find { |ch| ch['name'] == name }
63 | end
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/lib/breacan/client/im.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Im
4 | def im_close(args)
5 | get 'im.close', query: args
6 | end
7 |
8 | def im_history(args)
9 | get 'im.history', query: args
10 | end
11 |
12 | def im_list(args)
13 | get 'im.list', query: args
14 | end
15 |
16 | def im_mark(args)
17 | get 'im.mark', query: args
18 | end
19 |
20 | def im_open(args)
21 | get 'im.open', query: args
22 | end
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/lib/breacan/client/oauth.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module OAuth
4 | def oauth_access(args)
5 | get 'oauth.access', query: args
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/breacan/client/rtm.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Rtm
4 | def rtm_start
5 | get 'rtm.start'
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/breacan/client/search.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Search
4 | def search_all(args)
5 | get 'serach.all', query: args
6 | end
7 |
8 | def search_files(args)
9 | get 'serach.files', query: args
10 | end
11 |
12 | def search_messages(args)
13 | get 'serach.messages', query: args
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/breacan/client/star.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Star
4 | def star_list(args)
5 | get 'star.list', query: args
6 | end
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/breacan/client/usergroups.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Usergroups
4 | def usergroups_create(args)
5 | get 'usergroups.create', query: args
6 | end
7 | alias_method :create_usergroup, :usergroups_create
8 |
9 | def usergroups_disable(args)
10 | get 'usergroups.disable', query: args
11 | end
12 | alias_method :disable_usergroup, :usergroups_disable
13 |
14 | def usergroups_enable(args)
15 | get 'usergroups.enable', query: args
16 | end
17 | alias_method :enable_usergroup, :usergroups_enable
18 |
19 | def usergroups_list(args = {})
20 | get 'usergroups.list', query: args
21 | end
22 | alias_method :usergroups, :usergroups_list
23 |
24 | def usergroups_update(args)
25 | get 'usergroups.update', query: args
26 | end
27 | alias_method :update_usergroup, :usergroups_update
28 |
29 | def usergroups_users_list(id, options = {})
30 | get 'usergroups.users.list', query: { usergroup: id }.merge(options)
31 | end
32 | alias_method :usergroup_users, :usergroups_users_list
33 |
34 | def usergroups_users_update(args)
35 | get 'usergroups.users.update', query: args
36 | end
37 | alias_method :update_usergroup_users, :usergroups_users_update
38 | end
39 | end
40 | end
41 |
--------------------------------------------------------------------------------
/lib/breacan/client/users.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Client
3 | module Users
4 | def users_get_presence(args)
5 | get 'users.getPresence', query: args
6 | end
7 | alias_method :user_presence, :users_get_presence
8 |
9 | def users_info(id, options = {})
10 | get 'users.info', query: { user: id }.merge(options)
11 | end
12 | alias_method :user, :users_info
13 |
14 | def users_list(args = {})
15 | get 'users.list', query: args
16 | end
17 | alias_method :users, :users_list
18 |
19 | def users_set_active
20 | get 'users.setActive'
21 | end
22 | alias_method :activate_user, :users_set_active
23 |
24 | def users_set_presence(args)
25 | get 'users.setPresence', query: args
26 | end
27 | alias_method :set_user_presence, :users_set_presence
28 |
29 | def user_by_name(name)
30 | users.find { |u| u if u.name == name }
31 | end
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/breacan/configurable.rb:
--------------------------------------------------------------------------------
1 | require 'breacan/response/custom'
2 |
3 | module Breacan
4 | module Configurable
5 | OPTIONS_KEYS = %i(
6 | access_token
7 | team
8 | api_endpoint
9 | web_endpoint
10 | user_agent
11 | media_type
12 | connection_options
13 | proxy
14 | middleware
15 | serializer
16 | auto_paginate
17 | )
18 |
19 | attr_accessor(*OPTIONS_KEYS)
20 |
21 | class << self
22 | def keys
23 | @keys ||= OPTIONS_KEYS
24 | end
25 | end
26 |
27 | def configure
28 | yield self
29 | end
30 |
31 | def api_endpoint
32 | File.join(@api_endpoint, '')
33 | end
34 |
35 | def web_endpoint
36 | File.join(@web_endpoint, '')
37 | end
38 |
39 | def reset!
40 |
41 | @access_token = ENV['BREACAN_ACCESS_TOKEN']
42 | @team = ENV['BREACAN_TEAM']
43 | @api_endpoint = ENV['BREACAN_API_ENDPOINT'] || 'https://slack.com/api/'
44 | @web_endpoint = ENV['BREACAN_WEB_ENDPOINT'] || "https://#{@team}.slack.com/"
45 | @user_agent = "Breacan Ruby Gem #{Breacan::VERSION}"
46 | @media_type = 'application/json'
47 | @connection_options = { headers: { accept: media_type, user_agent: user_agent } }
48 | @proxy = ENV['BREACAN_PROXY']
49 | @middleware = default_builder
50 | @serializer = default_serializer
51 | @auto_paginate = !!ENV['BREACAN_AUTO_PAGINATE']
52 |
53 | self
54 | end
55 | alias setup reset!
56 |
57 | def default_serializer
58 | Sawyer::Serializer.any_json
59 | end
60 |
61 | def default_builder
62 | builder = if defined? Faraday::RackBuilder
63 | Faraday::RackBuilder
64 | else
65 | Faraday::Builder
66 | end
67 |
68 | builder.new do |c|
69 | c.response :breacan_custom
70 | c.adapter Faraday.default_adapter
71 | end
72 | end
73 |
74 | def options
75 | Hash[Breacan::Configurable.keys.map { |key|
76 | [key, instance_variable_get(:"@#{key}")]
77 | }]
78 | end
79 | end
80 | end
81 |
--------------------------------------------------------------------------------
/lib/breacan/error.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | class Error < StandardError
3 | def self.from_response(response)
4 | status = response[:status].to_i
5 | if klass = case status
6 | when 400 then Breacan::BadRequest
7 | when 401 then Breacan::Unauthorized
8 | when 403 then Breacan::Forbidden
9 | when 404 then Breacan::NotFound
10 | when 406 then Breacan::NotAcceptable
11 | when 409 then Breacan::Conflict
12 | when 415 then Breacan::UnsupportedMediaType
13 | when 422 then Breacan::UnprocessableEntity
14 | when 400..499 then Breacan::ClientError
15 | when 500 then Breacan::InternalServerError
16 | when 501 then Breacan::NotImplemented
17 | when 502 then Breacan::BadGateway
18 | when 503 then Breacan::ServiceUnavailable
19 | when 500..599 then Breacan::ServerError
20 | end
21 | klass.new(response)
22 | end
23 | end
24 |
25 | def self.from_body(response, body)
26 | Breacan::BadRequest.new(response) unless body[:ok]
27 | end
28 |
29 | def initialize(response = nil)
30 | @response = response
31 | super(build_error_message)
32 | end
33 |
34 | def errors
35 | if data && data.is_a?(Hash)
36 | data[:errors] || []
37 | else
38 | []
39 | end
40 | end
41 |
42 | private
43 |
44 | def data
45 | @data ||=
46 | if (body = @response[:body]) && !body.empty?
47 | if body.is_a?(String) &&
48 | @response[:response_headers] &&
49 | @response[:response_headers][:content_type] =~ /json/
50 |
51 | Sawyer::Agent.serializer.decode(body)
52 | else
53 | body
54 | end
55 | else
56 | nil
57 | end
58 | end
59 |
60 | def response_message
61 | case data
62 | when Hash
63 | data[:message]
64 | when String
65 | data
66 | end
67 | end
68 |
69 | def response_error
70 | "Error: #{data[:error]}" if data.is_a?(Hash) && data[:error]
71 | end
72 |
73 | def build_error_message
74 | return nil if @response.nil?
75 |
76 | message = "#{@response[:method].to_s.upcase} "
77 | message << redact_url(@response[:url].to_s) + ": "
78 | message << "#{@response[:status]} - "
79 | message << "#{response_message}" unless response_message.nil?
80 | message << "#{response_error}" unless response_error.nil?
81 | message
82 | end
83 |
84 | def redact_url(url_string)
85 | %w[token client_secret access_token].each do |token|
86 | url_string.gsub!(/#{token}=\S+/, "#{token}=(redacted)") if url_string.include? token
87 | end
88 | url_string
89 | end
90 | end
91 |
92 | class ClientError < Error; end
93 | class BadRequest < ClientError; end
94 | class Unauthorized < ClientError; end
95 | class Forbidden < ClientError; end
96 | class TooManyRequests < Forbidden; end
97 | class TooManyLoginAttempts < Forbidden; end
98 | class NotFound < ClientError; end
99 | class NotAcceptable < ClientError; end
100 | class Conflict < ClientError; end
101 | class UnsupportedMediaType < ClientError; end
102 | class UnprocessableEntity < ClientError; end
103 | class ServerError < Error; end
104 | class InternalServerError < ServerError; end
105 | class NotImplemented < ServerError; end
106 | class BadGateway < ServerError; end
107 | class ServiceUnavailable < ServerError; end
108 | class MissingContentType < ArgumentError; end
109 | end
110 |
--------------------------------------------------------------------------------
/lib/breacan/response/custom.rb:
--------------------------------------------------------------------------------
1 | require 'faraday'
2 | require 'breacan/error'
3 |
4 | module Breacan
5 | module Response
6 | # NOTE: Since faraday v.2, `Faraday::Response::Middleware` has been removed. We can use `Faraday::Middleware` instead.
7 | # ref: https://github.com/lostisland/faraday/blob/c9cc1b30ecebcd57beffa67d275f68742b5b05c5/UPGRADING.md?plain=1#L128
8 | middleware_base = defined?(Faraday::Response::Middleware) ? Faraday::Response::Middleware : Faraday::Middleware
9 |
10 | class Custom < middleware_base
11 | private
12 |
13 | def on_complete(res)
14 | if error = Breacan::Error.from_response(res)
15 | raise error
16 | end
17 |
18 | return if res[:body].empty?
19 |
20 | body = Sawyer::Agent.serializer.decode(res[:body])
21 | if body[:ok]
22 | res[:body].gsub!('"ok":true,', '')
23 | end
24 |
25 | if error = Breacan::Error.from_body(res, body)
26 | raise error
27 | end
28 | end
29 | end
30 |
31 | Faraday::Response.register_middleware \
32 | breacan_custom: -> { Breacan::Response::Custom }
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/breacan/version.rb:
--------------------------------------------------------------------------------
1 | module Breacan
2 | VERSION = '0.11.0'
3 | end
4 |
--------------------------------------------------------------------------------