slack-api-wrapper 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in slack.gemspec
4
+ gemspec
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 [![Build Status](https://travis-ci.org/gssbzn/slack-api-wrapper.svg)](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,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,6 @@
1
+ require_relative 'oauth2/flow_base'
2
+ require_relative 'oauth2/flow'
3
+ module Slack
4
+ module Oauth2
5
+ end
6
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ module Slack
2
+ VERSION = "0.0.2"
3
+ 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,10 @@
1
+ module Slack
2
+ module Web
3
+ module Auth
4
+ def auth_test
5
+ response = @session.do_get "auth.test"
6
+ Slack::parse_response(response)
7
+ end
8
+ end
9
+ end
10
+ 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,13 @@
1
+ module Slack
2
+ module Web
3
+ module Emoji
4
+ SCOPE = "emoji"
5
+
6
+ # Lists custom emoji for a team.
7
+ def emoji_list
8
+ response = @session.do_get "#{SCOPE}.list"
9
+ Slack::parse_response(response)
10
+ end
11
+ end
12
+ end
13
+ 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
@@ -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,13 @@
1
+ module Slack
2
+ module Web
3
+ module Stars
4
+ SCOPE = "users"
5
+
6
+ # Lists stars for a user.
7
+ def stars_list(user, count, page)
8
+ raise Slack::Error("Not yet implemented, feel free to make a pull request")
9
+ end
10
+
11
+ end
12
+ end
13
+ 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
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Slack::Oauth2 do
4
+ it 'do something' do
5
+ skip
6
+ end
7
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'slack-api-wrapper'
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