slack-api-wrapper 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +42 -0
- data/Rakefile +7 -0
- data/lib/slack-api-wrapper.rb +87 -0
- data/lib/slack/client.rb +20 -0
- data/lib/slack/error.rb +21 -0
- data/lib/slack/oauth2.rb +6 -0
- data/lib/slack/oauth2/flow.rb +155 -0
- data/lib/slack/oauth2/flow_base.rb +78 -0
- data/lib/slack/session.rb +77 -0
- data/lib/slack/version.rb +3 -0
- data/lib/slack/web.rb +28 -0
- data/lib/slack/web/auth.rb +10 -0
- data/lib/slack/web/channels.rb +82 -0
- data/lib/slack/web/chat.rb +44 -0
- data/lib/slack/web/emoji.rb +13 -0
- data/lib/slack/web/files.rb +53 -0
- data/lib/slack/web/groups.rb +88 -0
- data/lib/slack/web/im.rb +34 -0
- data/lib/slack/web/search.rb +23 -0
- data/lib/slack/web/stars.rb +13 -0
- data/lib/slack/web/users.rb +38 -0
- data/slack-api-wrapper.gemspec +27 -0
- data/spec/slack/client_spec.rb +15 -0
- data/spec/slack/oauth2/flow_base_spec.rb +0 -0
- data/spec/slack/oauth2/flow_spec.rb +0 -0
- data/spec/slack/oauth2_spec.rb +7 -0
- data/spec/slack_spec.rb +30 -0
- data/spec/spec_helper.rb +3 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9c18b521343ae2907134d7af29d23616e0990ec2
|
4
|
+
data.tar.gz: a8fc73773601ce072195cf08bde1bf0247b7e3db
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1b4e7a04162651cbf861fd47928ce96735666cb5f942b2d51d3f103f6d948c8e2871606e37e0f758c4bba02617a100aaa4766c26922514262bcbeb5ec402fd57
|
7
|
+
data.tar.gz: d667a8f1236fa4cf4bb5c337c1a8a0ae460e11741b48fa1020bdc9f9f03b6bcf796e16a37bf513080469a5e60b7e54ef166a22e37f77cdf2c4d128a7004337fc
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Gustavo Bazan
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Slack API Wrapper [](https://travis-ci.org/gssbzn/slack-api-wrapper)
|
2
|
+
=========================
|
3
|
+
|
4
|
+
A library that provides a plain function-call interface to the Slack API web endpoints.
|
5
|
+
|
6
|
+
This a work in progress, many API endpoint implementations are still missing,
|
7
|
+
I expect to add them as soon as possible or you can help by making a pull request.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
Add this line to your application's Gemfile:
|
12
|
+
|
13
|
+
gem 'slack-api-wrapper'
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install slack-api-wrapper
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
You can see a demo here [slack-web-test](https://github.com/gssbzn/slack-web-test)
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it ( https://github.com/gssbzn/slack-api-wrapper/fork )
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create a new Pull Request
|
36
|
+
|
37
|
+
|
38
|
+
## License
|
39
|
+
|
40
|
+
MIT License. Copyright 2015 Gustavo Bazan. http://gustavobazan.com
|
41
|
+
|
42
|
+
This software is not created by, affiliated with, or supported by Slack Technologies, Inc.
|
data/Rakefile
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'cgi'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require_relative "slack/version"
|
6
|
+
require_relative "slack/error"
|
7
|
+
require_relative "slack/session"
|
8
|
+
require_relative "slack/oauth2"
|
9
|
+
require_relative "slack/client"
|
10
|
+
|
11
|
+
module Slack # :nodoc:
|
12
|
+
WEB_SERVER = 'slack.com'
|
13
|
+
API_SERVER = "#{WEB_SERVER}/api"
|
14
|
+
|
15
|
+
#
|
16
|
+
def self.clean_params(params)
|
17
|
+
r = {}
|
18
|
+
params.each do |k,v|
|
19
|
+
r[k] = v.to_s unless v.nil?
|
20
|
+
end
|
21
|
+
r
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
def self.make_query_string(params)
|
26
|
+
clean_params(params).collect {|k,v|
|
27
|
+
CGI.escape(k) + "=" + CGI.escape(v)
|
28
|
+
}.join("&")
|
29
|
+
end
|
30
|
+
|
31
|
+
#
|
32
|
+
def self.do_http(uri, request) # :nodoc:
|
33
|
+
|
34
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
35
|
+
|
36
|
+
http.use_ssl = true
|
37
|
+
|
38
|
+
# Let then know about us
|
39
|
+
request['User-Agent'] = "SlackRubyAPIWrapper"
|
40
|
+
|
41
|
+
begin
|
42
|
+
http.request(request)
|
43
|
+
rescue OpenSSL::SSL::SSLError => e
|
44
|
+
raise SlackError.new("SSL error connecting to Slack.")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Parse response. You probably shouldn't be calling this directly. This takes responses from the server
|
49
|
+
# and parses them. It also checks for errors and raises exceptions with the appropriate messages.
|
50
|
+
def self.parse_response(response, raw=false) # :nodoc:
|
51
|
+
if response.kind_of?(Net::HTTPServerError)
|
52
|
+
raise Slack.new("Slack Server Error: #{response} - #{response.body}", response)
|
53
|
+
elsif response.kind_of?(Net::HTTPUnauthorized)
|
54
|
+
raise SlackAuthError.new("User is not authenticated.", response)
|
55
|
+
elsif !response.kind_of?(Net::HTTPSuccess)
|
56
|
+
begin
|
57
|
+
d = JSON.parse(response.body)
|
58
|
+
rescue
|
59
|
+
raise SlackError.new("Slack Server Error: body=#{response.body}", response)
|
60
|
+
end
|
61
|
+
if d['error']
|
62
|
+
raise SlackError.new(d['error'], response)
|
63
|
+
else
|
64
|
+
raise SlackError.new(response.body, response)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
return response.body if raw
|
69
|
+
|
70
|
+
begin
|
71
|
+
return JSON.parse(response.body)
|
72
|
+
rescue JSON::ParserError
|
73
|
+
raise SlackError.new("Unable to parse JSON response: #{response.body}", response)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# A string comparison function that is resistant to timing attacks. If you're comparing a
|
78
|
+
# string you got from the outside world with a string that is supposed to be a secret, use
|
79
|
+
# this function to check equality.
|
80
|
+
def self.safe_string_equals(a, b)
|
81
|
+
if a.length != b.length
|
82
|
+
false
|
83
|
+
else
|
84
|
+
a.chars.zip(b.chars).map {|ac,bc| ac == bc}.all?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/slack/client.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'session'
|
2
|
+
require_relative 'web'
|
3
|
+
|
4
|
+
module Slack
|
5
|
+
# Use this class to make Slack API calls. You'll need to obtain an OAuth 2 access token
|
6
|
+
# first; you can get one using either SlackOAuth2Flow.
|
7
|
+
class Client
|
8
|
+
include Web
|
9
|
+
|
10
|
+
# Args:
|
11
|
+
# * +oauth2_access_token+: Obtained via Slack::OAuth2::Flow or Slack::OAuth2::FlowNoRedirect.
|
12
|
+
def initialize(oauth2_access_token)
|
13
|
+
if oauth2_access_token.is_a?(String)
|
14
|
+
@session = OAuth2Session.new(oauth2_access_token)
|
15
|
+
else
|
16
|
+
raise ArgumentError.new("oauth2_access_token doesn't have a valid type")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/slack/error.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This is the usual error raised on any Slack related Errors
|
2
|
+
module Slack
|
3
|
+
class Error < RuntimeError
|
4
|
+
attr_accessor :http_response, :error
|
5
|
+
def initialize(error, http_response=nil)
|
6
|
+
@error = error
|
7
|
+
@http_response = http_response
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"#{error}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# This is the error raised on Authentication failures. Usually this means
|
16
|
+
# one of three things
|
17
|
+
# * Your user failed to go to the authorize url and approve your application
|
18
|
+
# * You set an invalid or expired token and secret on your Session
|
19
|
+
# * Your user deauthorized the application after you stored a valid token and secret
|
20
|
+
class AuthError < Error; end
|
21
|
+
end
|
data/lib/slack/oauth2.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
require_relative 'flow_base'
|
4
|
+
|
5
|
+
module Slack
|
6
|
+
module OAuth2
|
7
|
+
# The standard OAuth 2 authorization helper. Use this if you're writing a web app.
|
8
|
+
class Flow < FlowBase
|
9
|
+
|
10
|
+
# * consumer_key: Your Slack API app's "app key"
|
11
|
+
# * consumer_secret: Your Slack API app's "app secret"
|
12
|
+
# * redirect_uri: The URI that the Slack server will redirect the user to after the user
|
13
|
+
# finishes authorizing your app. This URI must be HTTPs-based and pre-registered with
|
14
|
+
# the Slack servers.
|
15
|
+
# * session: A hash that represents the current web app session (will be used to save the CSRF
|
16
|
+
# token)
|
17
|
+
# * csrf_token_key: The key to use when storing the CSRF token in the session (for example,
|
18
|
+
# :slack_auth_csrf_token)
|
19
|
+
def initialize(consumer_key, consumer_secret, redirect_uri, scope, team, session, csrf_token_session_key)
|
20
|
+
super(consumer_key, consumer_secret, scope, team)
|
21
|
+
unless redirect_uri.is_a?(String)
|
22
|
+
raise ArgumentError, "redirect_uri must be a String, got #{consumer_secret.inspect}"
|
23
|
+
end
|
24
|
+
@redirect_uri = redirect_uri
|
25
|
+
@session = session
|
26
|
+
@csrf_token_session_key = csrf_token_session_key
|
27
|
+
end
|
28
|
+
|
29
|
+
# Starts the OAuth 2 authorizaton process, which involves redirecting the user to
|
30
|
+
# the returned "authorization URL" (a URL on the Slack website). When the user then
|
31
|
+
# either approves or denies your app access, Slack will redirect them to the
|
32
|
+
# redirect_uri you provided to the constructor, at which point you should call finish()
|
33
|
+
# to complete the process.
|
34
|
+
#
|
35
|
+
# This function will also save a CSRF token to the session and csrf_token_session_key
|
36
|
+
# you provided to the constructor. This CSRF token will be checked on finish() to prevent
|
37
|
+
# request forgery.
|
38
|
+
#
|
39
|
+
# * url_state: Any data you would like to keep in the URL through the authorization
|
40
|
+
# process. This exact value will be returned to you by finish().
|
41
|
+
#
|
42
|
+
# Returns the URL to redirect the user to.
|
43
|
+
def start(url_state=nil)
|
44
|
+
unless url_state.nil? or url_state.is_a?(String)
|
45
|
+
raise ArgumentError, "url_state must be a String"
|
46
|
+
end
|
47
|
+
|
48
|
+
csrf_token = SecureRandom.base64(16)
|
49
|
+
state = csrf_token
|
50
|
+
unless url_state.nil?
|
51
|
+
state += "|" + url_state
|
52
|
+
end
|
53
|
+
@session[@csrf_token_session_key] = csrf_token
|
54
|
+
_get_authorize_url(@redirect_uri, state)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Call this after the user has visited the authorize URL (see: start()), approved your app,
|
58
|
+
# and was redirected to your redirect URI.
|
59
|
+
#
|
60
|
+
# * query_params: The query params on the GET request to your redirect URI.
|
61
|
+
#
|
62
|
+
# Returns a tuple of (access_token, scope, url_state). access_token can be used to
|
63
|
+
# construct a SlackClient. scpe is the Slack scope the user that jsut approved
|
64
|
+
# your app. url_state is the value you originally passed in to start().
|
65
|
+
#
|
66
|
+
# Can throw BadRequestError, BadStateError, CsrfError, NotApprovedError,
|
67
|
+
# ProviderError.
|
68
|
+
def finish(query_params)
|
69
|
+
csrf_token_from_session = @session[@csrf_token_session_key]
|
70
|
+
|
71
|
+
# Check well-formedness of request.
|
72
|
+
|
73
|
+
# Check well-formedness of request.
|
74
|
+
|
75
|
+
state = query_params['state']
|
76
|
+
if state.nil?
|
77
|
+
raise BadRequestError.new("Missing query parameter 'state'.")
|
78
|
+
end
|
79
|
+
code = query_params['code']
|
80
|
+
|
81
|
+
error = query_params['error']
|
82
|
+
|
83
|
+
unless (error.nil? || code.nil?)
|
84
|
+
raise BadRequestError.new("Query parameters 'code' and 'error' are both set;" +
|
85
|
+
" only one must be set.")
|
86
|
+
end
|
87
|
+
if error.nil? and code.nil?
|
88
|
+
raise BadRequestError.new("Neither query parameter 'code' or 'error' is set.")
|
89
|
+
end
|
90
|
+
|
91
|
+
# Check CSRF token
|
92
|
+
|
93
|
+
if csrf_token_from_session.nil?
|
94
|
+
raise BadStateError.new("Missing CSRF token in session.");
|
95
|
+
end
|
96
|
+
unless csrf_token_from_session.length > 20
|
97
|
+
raise RuntimeError.new("CSRF token unexpectedly short: #{csrf_token_from_session.inspect}")
|
98
|
+
end
|
99
|
+
|
100
|
+
split_pos = state.index('|')
|
101
|
+
if split_pos.nil?
|
102
|
+
given_csrf_token = state
|
103
|
+
url_state = nil
|
104
|
+
else
|
105
|
+
given_csrf_token, url_state = state.split('|', 2)
|
106
|
+
end
|
107
|
+
unless Slack::safe_string_equals(csrf_token_from_session, given_csrf_token)
|
108
|
+
raise CsrfError.new("Expected #{csrf_token_from_session.inspect}, " +
|
109
|
+
"got #{given_csrf_token.inspect}.")
|
110
|
+
end
|
111
|
+
@session.delete(@csrf_token_session_key)
|
112
|
+
|
113
|
+
# Check for error identifier
|
114
|
+
|
115
|
+
unless error.nil?
|
116
|
+
if error == 'access_denied'
|
117
|
+
# The user clicked "Deny"
|
118
|
+
raise NotApprovedError.new("No additional description from Slack.")
|
119
|
+
else
|
120
|
+
raise ProviderError.new(error)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# If everything went ok, make the network call to get an access token.
|
125
|
+
|
126
|
+
access_token, scope = _finish(code, @redirect_uri)
|
127
|
+
return access_token, scope, url_state
|
128
|
+
end
|
129
|
+
|
130
|
+
# Thrown if the redirect URL was missing parameters or if the given parameters were not valid.
|
131
|
+
#
|
132
|
+
# The recommended action is to show an HTTP 400 error page.
|
133
|
+
class BadRequestError < Exception; end
|
134
|
+
|
135
|
+
# Thrown if all the parameters are correct, but there's no CSRF token in the session. This
|
136
|
+
# probably means that the session expired.
|
137
|
+
#
|
138
|
+
# The recommended action is to redirect the user's browser to try the approval process again.
|
139
|
+
class BadStateError < Exception; end
|
140
|
+
|
141
|
+
# The user chose not to approve your app.
|
142
|
+
class NotApprovedError < Exception; end
|
143
|
+
|
144
|
+
# Thrown if the given 'state' parameter doesn't contain the CSRF token from the user's session.
|
145
|
+
# This is blocked to prevent CSRF attacks.
|
146
|
+
#
|
147
|
+
# The recommended action is to respond with an HTTP 403 error page.
|
148
|
+
class CsrfError < Exception; end
|
149
|
+
|
150
|
+
# Slack redirected to your redirect URI with some unexpected error identifier and error
|
151
|
+
# message.
|
152
|
+
class ProviderError < Exception; end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Slack
|
4
|
+
module OAuth2
|
5
|
+
# Base class for the OAuth 2 authorization helpers.
|
6
|
+
class FlowBase # :nodoc:
|
7
|
+
def initialize(consumer_key, consumer_secret, scope, team)
|
8
|
+
unless consumer_key.is_a?(String)
|
9
|
+
raise ArgumentError, "consumer_key must be a String, got #{consumer_key.inspect}"
|
10
|
+
end
|
11
|
+
unless consumer_secret.is_a?(String)
|
12
|
+
raise ArgumentError, "consumer_secret must be a String, got #{consumer_secret.inspect}"
|
13
|
+
end
|
14
|
+
unless scope.is_a?(String)
|
15
|
+
raise ArgumentError, "scope must be a String, got #{scope.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
@consumer_key = consumer_key
|
19
|
+
@consumer_secret = consumer_secret
|
20
|
+
@scope = scope
|
21
|
+
@team = team
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def _get_authorize_url(redirect_uri, state)
|
27
|
+
params = {
|
28
|
+
"client_id" => @consumer_key,
|
29
|
+
"redirect_uri" => redirect_uri,
|
30
|
+
"scope" => @scope,
|
31
|
+
"state" => state,
|
32
|
+
"team" => @team
|
33
|
+
}
|
34
|
+
|
35
|
+
host = Slack::WEB_SERVER
|
36
|
+
path = "/oauth/authorize"
|
37
|
+
|
38
|
+
target = URI::Generic.new("https", nil, host, nil, nil, path, nil, nil, nil)
|
39
|
+
target.query = Slack::make_query_string(params)
|
40
|
+
|
41
|
+
target.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
# Finish the OAuth 2 authorization process. If you used a redirect_uri, pass that in.
|
45
|
+
# Will return an access token string that you can use with SlackClient.
|
46
|
+
def _finish(code, original_redirect_uri)
|
47
|
+
|
48
|
+
raise ArgumentError, "code must be a String" unless code.is_a?(String)
|
49
|
+
|
50
|
+
uri = URI.parse("https://#{Slack::API_SERVER}/oauth.access")
|
51
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
52
|
+
|
53
|
+
params = {
|
54
|
+
"client_id" => @consumer_key,
|
55
|
+
"client_secret" => @consumer_secret,
|
56
|
+
"code" => code,
|
57
|
+
"redirect_uri" => original_redirect_uri
|
58
|
+
}
|
59
|
+
|
60
|
+
request.set_form_data(Slack::clean_params(params))
|
61
|
+
|
62
|
+
response = Slack::do_http(uri, request)
|
63
|
+
|
64
|
+
j = Slack::parse_response(response)
|
65
|
+
["access_token", "scope"].each do |k|
|
66
|
+
unless j.has_key?(k)
|
67
|
+
raise Slack::Error.new("Bad response from /token: missing \"#{k}\".")
|
68
|
+
end
|
69
|
+
unless j[k].is_a?(String)
|
70
|
+
raise Slack::Error.new("Bad response from /token: field \"#{k}\" is not a string.")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
return j['access_token'], j['scope']
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Slack
|
2
|
+
|
3
|
+
class OAuth2Session # :nodoc:
|
4
|
+
|
5
|
+
def initialize(oauth2_access_token)
|
6
|
+
unless oauth2_access_token.is_a?(String)
|
7
|
+
raise "bad type for oauth2_access_token (expecting String)"
|
8
|
+
end
|
9
|
+
@access_token = oauth2_access_token
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def build_url(path)
|
15
|
+
host = Slack::WEB_SERVER
|
16
|
+
full_path = "/api/#{path}"
|
17
|
+
URI::HTTPS.build({host: host, path: full_path})
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_url_with_params(path, params) # :nodoc:
|
21
|
+
target = build_url(path)
|
22
|
+
target.query = Slack::make_query_string(params)
|
23
|
+
target
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def do_http(uri, request) # :nodoc:
|
29
|
+
Slack::do_http(uri, request)
|
30
|
+
end
|
31
|
+
|
32
|
+
public
|
33
|
+
|
34
|
+
def do_get(path, params=nil, headers=nil) # :nodoc:
|
35
|
+
params ||= {}
|
36
|
+
params["token"] = @access_token
|
37
|
+
uri = build_url_with_params(path, params)
|
38
|
+
do_http(uri, Net::HTTP::Get.new(uri.request_uri))
|
39
|
+
end
|
40
|
+
|
41
|
+
def do_http_with_body(uri, request, body)
|
42
|
+
if body != nil
|
43
|
+
if body.is_a?(Hash)
|
44
|
+
request.set_form_data(Slack::clean_params(body))
|
45
|
+
elsif body.respond_to?(:read)
|
46
|
+
if body.respond_to?(:length)
|
47
|
+
request["Content-Length"] = body.length.to_s
|
48
|
+
elsif body.respond_to?(:stat) && body.stat.respond_to?(:size)
|
49
|
+
request["Content-Length"] = body.stat.size.to_s
|
50
|
+
else
|
51
|
+
raise ArgumentError, "Don't know how to handle 'body' (responds to 'read' but not to 'length' or 'stat.size')."
|
52
|
+
end
|
53
|
+
request.body_stream = body
|
54
|
+
else
|
55
|
+
s = body.to_s
|
56
|
+
request["Content-Length"] = s.length
|
57
|
+
request.body = s
|
58
|
+
end
|
59
|
+
end
|
60
|
+
do_http(uri, request)
|
61
|
+
end
|
62
|
+
|
63
|
+
def do_post(path, params=nil, headers=nil) # :nodoc:
|
64
|
+
params ||= {}
|
65
|
+
params["token"] = @access_token
|
66
|
+
uri = build_url(path)
|
67
|
+
do_http_with_body(uri, Net::HTTP::Post.new(uri.request_uri, headers), params)
|
68
|
+
end
|
69
|
+
|
70
|
+
def do_put(path, params=nil, headers=nil, body=nil) # :nodoc:
|
71
|
+
params ||= {}
|
72
|
+
params["token"] = @access_token
|
73
|
+
uri = build_url_with_params(path, params)
|
74
|
+
do_http_with_body(uri, Net::HTTP::Put.new(uri.request_uri, headers), body)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/slack/web.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'web/auth'
|
2
|
+
require_relative 'web/channels'
|
3
|
+
require_relative 'web/chat'
|
4
|
+
require_relative 'web/emoji'
|
5
|
+
require_relative 'web/files'
|
6
|
+
require_relative 'web/groups'
|
7
|
+
require_relative 'web/im'
|
8
|
+
require_relative 'web/search'
|
9
|
+
require_relative 'web/stars'
|
10
|
+
require_relative 'web/users'
|
11
|
+
require_relative 'error'
|
12
|
+
|
13
|
+
module Slack
|
14
|
+
module Web
|
15
|
+
include Auth
|
16
|
+
include Channels
|
17
|
+
include Chat
|
18
|
+
include Emoji
|
19
|
+
include Files
|
20
|
+
include Groups
|
21
|
+
include Im
|
22
|
+
include Stars
|
23
|
+
include Search
|
24
|
+
include Users
|
25
|
+
|
26
|
+
class NotImplementedError < Exception; end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Channels
|
4
|
+
SCOPE = "channels"
|
5
|
+
|
6
|
+
# Archives a channel.
|
7
|
+
def channels_archive(channel)
|
8
|
+
response = @session.do_get "#{SCOPE}.archive", "channel" => channel
|
9
|
+
Slack::parse_response(response)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Creates a channel.
|
13
|
+
def channels_create(name)
|
14
|
+
response = @session.do_get "#{SCOPE}.create", "name" => name
|
15
|
+
Slack::parse_response(response)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Fetches history of messages and events from a channel.
|
19
|
+
def channels_history(channel, latest, oldest, inclusive, count)
|
20
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
21
|
+
end
|
22
|
+
|
23
|
+
# Gets information about a channel.
|
24
|
+
def channels_info(channel)
|
25
|
+
response = @session.do_get "#{SCOPE}.info", "channel" => channel
|
26
|
+
Slack::parse_response(response)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Invites a user to a channel.
|
30
|
+
def channels_invite(channel, user)
|
31
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
32
|
+
end
|
33
|
+
|
34
|
+
# Joins a channel, creating it if needed.
|
35
|
+
def channels_join(name)
|
36
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
37
|
+
end
|
38
|
+
|
39
|
+
# Removes a user from a channel.
|
40
|
+
def channels_kick(channel, user)
|
41
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
42
|
+
end
|
43
|
+
|
44
|
+
# Leaves a channel.
|
45
|
+
def channels_leave(channel)
|
46
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
47
|
+
end
|
48
|
+
|
49
|
+
# Lists all channels in a Slack team.
|
50
|
+
def channels_list(exclude_archived=0)
|
51
|
+
response = @session.do_get "#{SCOPE}.list", "exclude_archived" => exclude_archived
|
52
|
+
Slack::parse_response(response)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Sets the read cursor in a channel.
|
56
|
+
def channels_mark(channel, ts)
|
57
|
+
raise Slack::Error("Not yet implemented, feel free to make a pull request")
|
58
|
+
end
|
59
|
+
|
60
|
+
# Renames a channel.
|
61
|
+
def channels_rename(channel, name)
|
62
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sets the purpose for a channel.
|
66
|
+
def channels_set_purpose(channel, purpose)
|
67
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Sets the topic for a channel.
|
71
|
+
def channels_set_topic(channel, topic)
|
72
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
73
|
+
end
|
74
|
+
|
75
|
+
# Unarchives a channel.
|
76
|
+
def channels_unarchive(channel)
|
77
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Chat
|
4
|
+
SCOPE = "chat"
|
5
|
+
|
6
|
+
# Deletes a message.
|
7
|
+
def chat_delete(ts, channel)
|
8
|
+
param = {
|
9
|
+
"ts" => ts,
|
10
|
+
"channel" => channel
|
11
|
+
}
|
12
|
+
response = @session.do_get "#{SCOPE}.delete", param
|
13
|
+
Slack::parse_response(response)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Sends a message to a channel.
|
17
|
+
def chat_post_message(channel, text, username, as_user= false, parse, link_names, attachments)
|
18
|
+
param = {
|
19
|
+
"channel" => channel,
|
20
|
+
"text" => text,
|
21
|
+
"username" => username,
|
22
|
+
"as_user" => as_user,
|
23
|
+
"parse" => parse,
|
24
|
+
"link_names" => link_names,
|
25
|
+
"attachments" => attachments
|
26
|
+
}
|
27
|
+
response = @session.do_get "#{SCOPE}.postMessage", param
|
28
|
+
Slack::parse_response(response)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Updates a message.
|
32
|
+
def chat_update(ts, channel, text)
|
33
|
+
param = {
|
34
|
+
"ts" => ts,
|
35
|
+
"channel" => channel,
|
36
|
+
"text" => text
|
37
|
+
}
|
38
|
+
response = @session.do_get "#{SCOPE}.update", param
|
39
|
+
Slack::parse_response(response)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Files
|
4
|
+
SCOPE = "files"
|
5
|
+
|
6
|
+
#Deletes a file.
|
7
|
+
def files_delete(file)
|
8
|
+
response = @session.do_get "#{SCOPE}.delete", "file" => file
|
9
|
+
Slack::parse_response(response)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets information about a team file.
|
13
|
+
def files_info(file, count=100, page=1)
|
14
|
+
param = {
|
15
|
+
"file" => file,
|
16
|
+
"count" => count,
|
17
|
+
"page" => page
|
18
|
+
}
|
19
|
+
response = @session.do_get "#{SCOPE}.info", param
|
20
|
+
Slack::parse_response(response)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Lists & filters team files.
|
24
|
+
def files_list(user, ts_from=0, ts_to=Time.now, types="all", count=100, page=1)
|
25
|
+
param = {
|
26
|
+
"user" => user,
|
27
|
+
"ts_from" => ts_from,
|
28
|
+
"ts_to" => ts_to,
|
29
|
+
"types" => types,
|
30
|
+
"count" => count,
|
31
|
+
"page" => page
|
32
|
+
}
|
33
|
+
response = @session.do_get "#{SCOPE}.list", param
|
34
|
+
Slack::parse_response(response)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Uploads or creates a file.
|
38
|
+
def files_upload(file, content, filetype, filename, title, initial_comment, channels)
|
39
|
+
param = {
|
40
|
+
"file" => file,
|
41
|
+
"content" => content,
|
42
|
+
"filetype" => filetype,
|
43
|
+
"filename" => filename,
|
44
|
+
"title" => title,
|
45
|
+
"initial_comment" => initial_comment,
|
46
|
+
"channels" => channels
|
47
|
+
}
|
48
|
+
response = @session.do_get "#{SCOPE}.upload", param
|
49
|
+
Slack::parse_response(response)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Groups
|
4
|
+
SCOPE = "groups"
|
5
|
+
|
6
|
+
# Archives a private group.
|
7
|
+
def groups_archive(channel)
|
8
|
+
response = @session.do_get "#{SCOPE}.archive", "channel" => channel
|
9
|
+
Slack::parse_response(response)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Closes a private group.
|
13
|
+
def groups_close(channel)
|
14
|
+
response = @session.do_get "#{SCOPE}.close", "channel" => channel
|
15
|
+
Slack::parse_response(response)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Creates a private group.
|
19
|
+
def groups_create(name)
|
20
|
+
response = @session.do_get "#{SCOPE}.create", "name" => name
|
21
|
+
Slack::parse_response(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Clones and archives a private group.
|
25
|
+
def groups_create_child(channel)
|
26
|
+
response = @session.do_get "#{SCOPE}.createChild", "channel" => channel
|
27
|
+
Slack::parse_response(response)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Fetches history of messages and events from a private group.
|
31
|
+
def groups_history(channel, latest, oldest, inclusive, count)
|
32
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Invites a user to a private group.
|
36
|
+
def groups_invite(channel, user)
|
37
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Removes a user from a private group.
|
41
|
+
def groups_kick(channel, user)
|
42
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Leaves a private group.
|
46
|
+
def groups_leave(channel)
|
47
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
48
|
+
end
|
49
|
+
|
50
|
+
# Lists private groups that the calling user has access to..
|
51
|
+
def groups_list(exclude_archived=0)
|
52
|
+
response = @session.do_get "#{SCOPE}.list", "exclude_archived" => exclude_archived
|
53
|
+
Slack::parse_response(response)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets the read cursor in a private group.
|
57
|
+
def groups_mark(channel, ts)
|
58
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
59
|
+
end
|
60
|
+
|
61
|
+
# Opens a private group.
|
62
|
+
def groups_open(channel)
|
63
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
64
|
+
end
|
65
|
+
|
66
|
+
# Renames a private group.
|
67
|
+
def groups_rename(channel, name)
|
68
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
69
|
+
end
|
70
|
+
|
71
|
+
# Sets the purpose for a private group.
|
72
|
+
def groups_set_purpose(channel, purpose)
|
73
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sets the topic for a private group.
|
77
|
+
def groups_set_topic(channel, topic)
|
78
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
79
|
+
end
|
80
|
+
|
81
|
+
# Unarchives a private group.
|
82
|
+
def groups_unarchive(channel)
|
83
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/slack/web/im.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Im
|
4
|
+
SCOPE = "im"
|
5
|
+
|
6
|
+
# Close a direct message channel.
|
7
|
+
def im_close(channel)
|
8
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
9
|
+
end
|
10
|
+
|
11
|
+
# Fetches history of messages and events from direct message channel.
|
12
|
+
def im_history(channel, latest, oldest, inclusive, count)
|
13
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Lists direct message channels for the calling user.
|
17
|
+
def im_list
|
18
|
+
response = @session.do_get "#{SCOPE}.list"
|
19
|
+
Slack::parse_response(response)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Sets the read cursor in a direct message channel.
|
23
|
+
def im_mark(channel, ts)
|
24
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
25
|
+
end
|
26
|
+
|
27
|
+
# Opens a direct message channel.
|
28
|
+
def im_open(user)
|
29
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Search
|
4
|
+
SCOPE = "search"
|
5
|
+
|
6
|
+
# Searches for messages and files matching a query.
|
7
|
+
def search_all(query, sort, sort_dir, highlight, count, page)
|
8
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
9
|
+
end
|
10
|
+
|
11
|
+
# Searches for files matching a query.
|
12
|
+
def search_files(query, sort, sort_dir, highlight, count, page)
|
13
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Searches for messages matching a query.
|
17
|
+
def search_messages(query, sort, sort_dir, highlight, count, page)
|
18
|
+
raise NotImplementedError.new("Not yet implemented, feel free to make a pull request")
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Slack
|
2
|
+
module Web
|
3
|
+
module Users
|
4
|
+
SCOPE = "users"
|
5
|
+
|
6
|
+
# Gets user presence information.
|
7
|
+
def users_get_presence(user)
|
8
|
+
response = @session.do_get "#{SCOPE}.getPresence", "user" => user
|
9
|
+
Slack::parse_response(response)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Gets information about a user.
|
13
|
+
def users_info(user)
|
14
|
+
response = @session.do_get "#{SCOPE}.info", "user" => user
|
15
|
+
Slack::parse_response(response)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Lists all users in a Slack team.
|
19
|
+
def users_list
|
20
|
+
response = @session.do_get "#{SCOPE}.list"
|
21
|
+
Slack::parse_response(response)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Marks a user as active.
|
25
|
+
def users_set_active
|
26
|
+
response = @session.do_get "#{SCOPE}.setActive"
|
27
|
+
Slack::parse_response(response)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Manually sets user presence.
|
31
|
+
def users_set_presence(presence)
|
32
|
+
response = @session.do_get "#{SCOPE}.setPresence", "presence" => presence
|
33
|
+
Slack::parse_response(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'slack/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "slack-api-wrapper"
|
8
|
+
spec.version = Slack::VERSION
|
9
|
+
spec.authors = ["Gustavo Bazan"]
|
10
|
+
spec.email = ["contacto@gustavobazan.com"]
|
11
|
+
spec.summary = "Slack API Wrapper"
|
12
|
+
spec.description = <<-EOF
|
13
|
+
A library that provides a plain function-call interface to the
|
14
|
+
Slack API web endpoints.
|
15
|
+
EOF
|
16
|
+
spec.homepage = ""
|
17
|
+
spec.license = "MIT"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
25
|
+
spec.add_development_dependency "rake", '~> 0'
|
26
|
+
spec.add_development_dependency "rspec", '~> 3.2', '>= 3.2.0'
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Slack::Client do
|
4
|
+
it 'Initialize' do
|
5
|
+
client = Slack::Client.new("")
|
6
|
+
expect(client).not_to be nil
|
7
|
+
end
|
8
|
+
it 'Validates token is string' do
|
9
|
+
expect{Slack::Client.new(1)}.to raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
it 'Validates unimplemented methods' do
|
12
|
+
client = Slack::Client.new("")
|
13
|
+
expect{client.groups_open("")}.to raise_error(Slack::Web::NotImplementedError)
|
14
|
+
end
|
15
|
+
end
|
File without changes
|
File without changes
|
data/spec/slack_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Slack do
|
4
|
+
it 'has a version number' do
|
5
|
+
expect(Slack::VERSION).not_to be nil
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'has web server domain' do
|
9
|
+
expect(Slack::WEB_SERVER).to eq('slack.com')
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has api uri' do
|
13
|
+
expect(Slack::API_SERVER).to eq('slack.com/api')
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '::clean_params' do
|
17
|
+
let(:params){ {"test_1"=>"test", "test_2" => nil} }
|
18
|
+
it 'removes nil params' do
|
19
|
+
expect(Slack::clean_params(params)).to eq({"test_1"=>"test"})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '::make_query_string' do
|
24
|
+
let(:params){ {"test_1"=>"test", "test_2" => "test"} }
|
25
|
+
it 'transform params to query string' do
|
26
|
+
expect(Slack::make_query_string(params)).to eq("test_1=test&test_2=test")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: slack-api-wrapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gustavo Bazan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: 3.2.0
|
51
|
+
type: :development
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - "~>"
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '3.2'
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 3.2.0
|
61
|
+
description: |2
|
62
|
+
A library that provides a plain function-call interface to the
|
63
|
+
Slack API web endpoints.
|
64
|
+
email:
|
65
|
+
- contacto@gustavobazan.com
|
66
|
+
executables: []
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- ".gitignore"
|
71
|
+
- ".rspec"
|
72
|
+
- ".travis.yml"
|
73
|
+
- Gemfile
|
74
|
+
- LICENSE.txt
|
75
|
+
- README.md
|
76
|
+
- Rakefile
|
77
|
+
- lib/slack-api-wrapper.rb
|
78
|
+
- lib/slack/client.rb
|
79
|
+
- lib/slack/error.rb
|
80
|
+
- lib/slack/oauth2.rb
|
81
|
+
- lib/slack/oauth2/flow.rb
|
82
|
+
- lib/slack/oauth2/flow_base.rb
|
83
|
+
- lib/slack/session.rb
|
84
|
+
- lib/slack/version.rb
|
85
|
+
- lib/slack/web.rb
|
86
|
+
- lib/slack/web/auth.rb
|
87
|
+
- lib/slack/web/channels.rb
|
88
|
+
- lib/slack/web/chat.rb
|
89
|
+
- lib/slack/web/emoji.rb
|
90
|
+
- lib/slack/web/files.rb
|
91
|
+
- lib/slack/web/groups.rb
|
92
|
+
- lib/slack/web/im.rb
|
93
|
+
- lib/slack/web/search.rb
|
94
|
+
- lib/slack/web/stars.rb
|
95
|
+
- lib/slack/web/users.rb
|
96
|
+
- slack-api-wrapper.gemspec
|
97
|
+
- spec/slack/client_spec.rb
|
98
|
+
- spec/slack/oauth2/flow_base_spec.rb
|
99
|
+
- spec/slack/oauth2/flow_spec.rb
|
100
|
+
- spec/slack/oauth2_spec.rb
|
101
|
+
- spec/slack_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
homepage: ''
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.4.4
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Slack API Wrapper
|
127
|
+
test_files:
|
128
|
+
- spec/slack/client_spec.rb
|
129
|
+
- spec/slack/oauth2/flow_base_spec.rb
|
130
|
+
- spec/slack/oauth2/flow_spec.rb
|
131
|
+
- spec/slack/oauth2_spec.rb
|
132
|
+
- spec/slack_spec.rb
|
133
|
+
- spec/spec_helper.rb
|