podio 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +94 -15
- data/lib/podio.rb +6 -12
- data/lib/podio/areas/conversation.rb +2 -2
- data/lib/podio/areas/email.rb +16 -2
- data/lib/podio/areas/notification.rb +1 -1
- data/lib/podio/areas/oauth.rb +18 -0
- data/lib/podio/areas/status.rb +9 -0
- data/lib/podio/areas/subscription.rb +1 -1
- data/lib/podio/client.rb +25 -12
- data/lib/podio/error.rb +16 -10
- data/lib/podio/middleware/date_conversion.rb +18 -21
- data/lib/podio/middleware/error_response.rb +26 -32
- data/lib/podio/middleware/json_request.rb +2 -0
- data/lib/podio/middleware/json_response.rb +6 -13
- data/lib/podio/middleware/oauth2.rb +1 -1
- data/lib/podio/middleware/response_recorder.rb +4 -6
- data/lib/podio/version.rb +1 -1
- data/podio.gemspec +1 -1
- data/test/client_test.rb +7 -15
- metadata +34 -17
- data/lib/podio/middleware/podio_api.rb +0 -19
- data/test/app_store_test.rb +0 -40
- data/test/contact_test.rb +0 -26
- data/test/item_test.rb +0 -37
- data/test/organization_test.rb +0 -20
- data/test/space_test.rb +0 -17
- data/test/widget_test.rb +0 -55
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
Podio
|
2
2
|
=====
|
3
3
|
|
4
|
-
Ruby
|
4
|
+
This is the official Ruby client for accessing the Podio API. Besides handling setup and authentication it also provides idiomatic Ruby methods for accessing most of the APIs operations. This client library is designed to be minimal and easily integrable into your projects.
|
5
|
+
|
5
6
|
|
6
7
|
Install
|
7
8
|
-------
|
@@ -11,27 +12,105 @@ Podio is packaged as a gem:
|
|
11
12
|
$ gem install podio
|
12
13
|
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
Configuration
|
16
|
+
-------------
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
The main way of using the Podio library is via a singleton client, which you set up like this:
|
19
|
+
|
20
|
+
Podio.setup(:api_key => 'YOUR_API_KEY', :api_secret => 'YOUR_API_SECRET')
|
21
|
+
|
22
|
+
This initializes a `Podio::Client` object and assigns it to a thread-local, which is used by all methods in this library.
|
23
|
+
|
24
|
+
|
25
|
+
Authentication
|
26
|
+
--------------
|
27
|
+
|
28
|
+
After the configuration you need to authenticate against the API. The client supports two ways of authentication:
|
29
|
+
|
30
|
+
### Web Server Flow
|
31
|
+
|
32
|
+
The default OAuth flow to be used when you authenticate Podio users from your web application.
|
33
|
+
|
34
|
+
Podio.client.authenticate_with_auth_code('AUTHORIZATION_CODE', redirect_uri)
|
35
|
+
|
36
|
+
### Username and Password Flow
|
37
|
+
|
38
|
+
If you're writing a batch job or are just playing around with the API, this is the easiest to get started. Do not use this for authenticating users other than yourself, the web server flow is meant for that.
|
39
|
+
|
40
|
+
Podio.client.authenticate_with_credentials('USERNAME', 'PASSWORD')
|
41
|
+
|
42
|
+
|
43
|
+
Basic Usage
|
44
|
+
-----------
|
45
|
+
|
46
|
+
After you configured the `Podio.client` singleton you can use all of the wrapper functions to do API requests. The functions are organized into modules corresponding to the official API documentation. The functions follow a common naming pattern that should be familiar to ActiveRecord users. For example:
|
47
|
+
|
48
|
+
# Getting an item
|
49
|
+
Podio::Item.find(42)
|
19
50
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
51
|
+
# Posting a status message on space with id 23
|
52
|
+
Podio::Status.create(23, {:value => 'This is the text of the status message'})
|
53
|
+
|
54
|
+
If there is a method missing or you want to do something special, you can use the Faraday connection directly. This allows you to do arbitrary HTTP requests to the Podio API with authentication, JSON parsing and error handling already taken care of. The same examples would look like this:
|
55
|
+
|
56
|
+
# Getting an item
|
57
|
+
response = Podio.connection.get('/item/42')
|
58
|
+
response.body
|
59
|
+
|
60
|
+
# Posting a status message on space with id 23
|
61
|
+
response = Podio.connection.post do |req|
|
62
|
+
req.url '/status/space/23/'
|
63
|
+
req.body = {:value => 'This is the text of the status message'}
|
24
64
|
end
|
65
|
+
response.body
|
66
|
+
|
67
|
+
All the wrapped methods either return a single Ruby hash, an array of Ruby hashes, or a simple Struct in case of pagination:
|
68
|
+
|
69
|
+
# Find all items in an app (paginated)
|
70
|
+
items = Podio::Item.find_all(app_id, :limit => 20)
|
71
|
+
|
72
|
+
# get count of returned items in this call
|
73
|
+
items.count
|
74
|
+
|
75
|
+
# get the returned items in an array
|
76
|
+
items.all
|
77
|
+
|
78
|
+
# get count of all items in this app
|
79
|
+
items.total_count
|
80
|
+
|
81
|
+
|
82
|
+
Error Handling
|
83
|
+
--------------
|
84
|
+
|
85
|
+
All unsuccessful responses returned by the API (everything that has a 4xx or 5xx HTTP status code) will throw an exception. All exceptions inherit from `Podio::PodioError` and have three additional properties which give you more information about the error:
|
86
|
+
|
87
|
+
begin
|
88
|
+
Podio::Space.create({:name => 'New Space', :org_id => 42})
|
89
|
+
rescue Podio::BadRequestError => exc
|
90
|
+
puts exc.response_body # parsed JSON response from the API
|
91
|
+
puts exc.response_status # status code of the response
|
92
|
+
puts exc.url # uri of the API request
|
93
|
+
|
94
|
+
# you normally want this one, a human readable error description
|
95
|
+
puts exc.response_body['error_description']
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
Full Example
|
100
|
+
------------
|
101
|
+
|
102
|
+
require 'rubygems'
|
103
|
+
require 'podio'
|
25
104
|
|
26
|
-
|
27
|
-
|
105
|
+
Podio.setup(:api_key => 'YOUR_API_KEY', :api_secret => 'YOUR_API_SECRET')
|
106
|
+
Podio.client.authenticate_with_credentials('YOUR_PODIO_ACCOUNT', 'YOUR_PODIO_PASSWORD')
|
28
107
|
|
29
|
-
#
|
30
|
-
my_orgs =
|
108
|
+
# Print a list of organizations I'm a member of
|
109
|
+
my_orgs = Podio::Organization.find_all
|
31
110
|
|
32
111
|
my_orgs.each do |org|
|
33
|
-
puts org
|
34
|
-
puts org
|
112
|
+
puts org['name']
|
113
|
+
puts org['url']
|
35
114
|
end
|
36
115
|
|
37
116
|
|
data/lib/podio.rb
CHANGED
@@ -1,29 +1,23 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
require 'active_support/core_ext'
|
3
3
|
|
4
|
+
require 'podio/error'
|
4
5
|
require 'podio/middleware/json_request'
|
5
6
|
require 'podio/middleware/date_conversion'
|
6
7
|
require 'podio/middleware/logger'
|
7
8
|
require 'podio/middleware/oauth2'
|
8
|
-
require 'podio/middleware/podio_api'
|
9
9
|
require 'podio/middleware/json_response'
|
10
10
|
require 'podio/middleware/error_response'
|
11
11
|
require 'podio/middleware/response_recorder'
|
12
12
|
|
13
13
|
module Podio
|
14
14
|
class << self
|
15
|
-
|
16
|
-
|
17
|
-
attr_accessor :api_url
|
18
|
-
attr_accessor :debug
|
19
|
-
|
20
|
-
def configure
|
21
|
-
yield self
|
22
|
-
true
|
15
|
+
def setup(options={})
|
16
|
+
Podio.client = Podio::Client.new(options)
|
23
17
|
end
|
24
18
|
|
25
19
|
def client
|
26
|
-
Thread.current[:podio_client]
|
20
|
+
Thread.current[:podio_client]
|
27
21
|
end
|
28
22
|
|
29
23
|
def client=(new_client)
|
@@ -38,7 +32,7 @@ module Podio
|
|
38
32
|
end
|
39
33
|
|
40
34
|
def connection
|
41
|
-
client.connection
|
35
|
+
client ? client.connection : nil
|
42
36
|
end
|
43
37
|
end
|
44
38
|
|
@@ -67,7 +61,6 @@ module Podio
|
|
67
61
|
end
|
68
62
|
|
69
63
|
autoload :Client, 'podio/client'
|
70
|
-
autoload :Error, 'podio/error'
|
71
64
|
autoload :ResponseWrapper, 'podio/response_wrapper'
|
72
65
|
|
73
66
|
autoload :Application, 'podio/areas/application'
|
@@ -81,6 +74,7 @@ module Podio
|
|
81
74
|
autoload :Email, 'podio/areas/email'
|
82
75
|
autoload :File, 'podio/areas/file'
|
83
76
|
autoload :Form, 'podio/areas/form'
|
77
|
+
autoload :Email, 'podio/areas/email'
|
84
78
|
autoload :Hook, 'podio/areas/hook'
|
85
79
|
autoload :Item, 'podio/areas/item'
|
86
80
|
autoload :Importer, 'podio/areas/importer'
|
@@ -27,10 +27,10 @@ module Podio
|
|
27
27
|
response.body
|
28
28
|
end
|
29
29
|
|
30
|
-
def create_reply(conversation_id, text)
|
30
|
+
def create_reply(conversation_id, text, file_ids = [])
|
31
31
|
response = Podio.connection.post do |req|
|
32
32
|
req.url "/conversation/#{conversation_id}/reply"
|
33
|
-
req.body = { :text => text }
|
33
|
+
req.body = { :text => text, :file_ids => file_ids }
|
34
34
|
end
|
35
35
|
response.body['message_id']
|
36
36
|
end
|
data/lib/podio/areas/email.rb
CHANGED
@@ -3,8 +3,22 @@ module Podio
|
|
3
3
|
include Podio::ResponseWrapper
|
4
4
|
extend self
|
5
5
|
|
6
|
-
def
|
7
|
-
Podio.connection.
|
6
|
+
def get_groups()
|
7
|
+
member Podio.connection.get { |req|
|
8
|
+
req.url("/email/group/", {})
|
9
|
+
}.body
|
8
10
|
end
|
11
|
+
|
12
|
+
def update_groups(options)
|
13
|
+
Podio.connection.put { |req|
|
14
|
+
req.url "/email/group/"
|
15
|
+
req.body = options
|
16
|
+
}.body
|
17
|
+
end
|
18
|
+
|
19
|
+
def unsubscribe(username)
|
20
|
+
Podio.connection.post("/email/unsubscribe/#{username}").status
|
21
|
+
end
|
22
|
+
|
9
23
|
end
|
10
24
|
end
|
data/lib/podio/areas/oauth.rb
CHANGED
@@ -34,6 +34,15 @@ module Podio
|
|
34
34
|
include Podio::ResponseWrapper
|
35
35
|
extend self
|
36
36
|
|
37
|
+
def create(attributes)
|
38
|
+
response = Podio.connection.post do |req|
|
39
|
+
req.url "/oauth/client/"
|
40
|
+
req.body = attributes
|
41
|
+
end
|
42
|
+
|
43
|
+
response.body['auth_client_id']
|
44
|
+
end
|
45
|
+
|
37
46
|
def create_admin(user_id, attributes)
|
38
47
|
response = Podio.connection.post do |req|
|
39
48
|
req.url "/oauth/client/user/#{user_id}/"
|
@@ -70,6 +79,11 @@ module Podio
|
|
70
79
|
def delete_grant(id)
|
71
80
|
response = Podio.connection.delete("/oauth/grant/client/#{id}")
|
72
81
|
|
82
|
+
response.status
|
83
|
+
end
|
84
|
+
|
85
|
+
def reset(id)
|
86
|
+
response = Podio.connection.post("/oauth/client/#{id}/reset")
|
73
87
|
response.status
|
74
88
|
end
|
75
89
|
|
@@ -77,6 +91,10 @@ module Podio
|
|
77
91
|
list Podio.connection.get("oauth/grant/client/").body
|
78
92
|
end
|
79
93
|
|
94
|
+
def find_all_for_current_user()
|
95
|
+
list Podio.connection.get("oauth/client/").body
|
96
|
+
end
|
97
|
+
|
80
98
|
def find_all_for_user(user_id)
|
81
99
|
list Podio.connection.get("oauth/client/user/#{user_id}/").body
|
82
100
|
end
|
data/lib/podio/areas/status.rb
CHANGED
@@ -6,5 +6,14 @@ module Podio
|
|
6
6
|
def find(id)
|
7
7
|
member Podio.connection.get("/status/#{id}").body
|
8
8
|
end
|
9
|
+
|
10
|
+
def create(space_id, attributes)
|
11
|
+
response = Podio.connection.post do |req|
|
12
|
+
req.url "/status/space/#{space_id}/"
|
13
|
+
req.body = attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
response.body['status_id']
|
17
|
+
end
|
9
18
|
end
|
10
19
|
end
|
data/lib/podio/client.rb
CHANGED
@@ -4,10 +4,10 @@ module Podio
|
|
4
4
|
attr_accessor :oauth_token, :stubs, :current_http_client
|
5
5
|
|
6
6
|
def initialize(options = {})
|
7
|
-
@api_url = options[:api_url] ||
|
8
|
-
@api_key = options[:api_key]
|
9
|
-
@api_secret = options[:api_secret]
|
10
|
-
@logger = options[:logger] || Podio::StdoutLogger.new(options[:debug]
|
7
|
+
@api_url = options[:api_url] || 'https://api.podio.com'
|
8
|
+
@api_key = options[:api_key]
|
9
|
+
@api_secret = options[:api_secret]
|
10
|
+
@logger = options[:logger] || Podio::StdoutLogger.new(options[:debug])
|
11
11
|
@oauth_token = options[:oauth_token]
|
12
12
|
@headers = options[:custom_headers] || {}
|
13
13
|
@adapter = options[:adapter] || Faraday.default_adapter
|
@@ -30,8 +30,19 @@ module Podio
|
|
30
30
|
setup_connections
|
31
31
|
end
|
32
32
|
|
33
|
-
#
|
34
|
-
def
|
33
|
+
# sign in as a user using the server side flow
|
34
|
+
def authenticate_with_auth_code(authorization_code, redirect_uri)
|
35
|
+
response = @oauth_connection.post do |req|
|
36
|
+
req.url '/oauth/token', :grant_type => 'authorization_code', :client_id => api_key, :client_secret => api_secret, :code => authorization_code, :redirect_uri => redirect_uri
|
37
|
+
end
|
38
|
+
|
39
|
+
@oauth_token = OAuthToken.new(response.body)
|
40
|
+
configure_oauth
|
41
|
+
@oauth_token
|
42
|
+
end
|
43
|
+
|
44
|
+
# Sign in as a user using credentials
|
45
|
+
def authenticate_with_credentials(username, password)
|
35
46
|
response = @oauth_connection.post do |req|
|
36
47
|
req.url '/oauth/token', :grant_type => 'password', :client_id => api_key, :client_secret => api_secret, :username => username, :password => password
|
37
48
|
end
|
@@ -40,9 +51,9 @@ module Podio
|
|
40
51
|
configure_oauth
|
41
52
|
@oauth_token
|
42
53
|
end
|
43
|
-
|
54
|
+
|
44
55
|
# Sign in as an app
|
45
|
-
def
|
56
|
+
def authenticate_with_app(app_id, app_token)
|
46
57
|
response = @oauth_connection.post do |req|
|
47
58
|
req.url '/oauth/token', :grant_type => 'app', :client_id => api_key, :client_secret => api_secret, :app_id => app_id, :app_token => app_token
|
48
59
|
end
|
@@ -81,14 +92,16 @@ module Podio
|
|
81
92
|
def configure_connection
|
82
93
|
Faraday::Connection.new(:url => api_url, :headers => configured_headers, :request => {:client => self}) do |builder|
|
83
94
|
builder.use Middleware::JsonRequest
|
84
|
-
builder.use Middleware::PodioApi
|
85
95
|
builder.use Middleware::OAuth2
|
86
96
|
builder.use Middleware::Logger
|
97
|
+
|
87
98
|
builder.adapter(*default_adapter)
|
88
|
-
|
89
|
-
|
90
|
-
builder.use Middleware::ErrorResponse
|
99
|
+
|
100
|
+
# first response middleware defined get's executed last
|
91
101
|
builder.use Middleware::DateConversion
|
102
|
+
builder.use Middleware::ErrorResponse
|
103
|
+
builder.use Middleware::JsonResponse
|
104
|
+
builder.use Middleware::ResponseRecorder if @record_mode
|
92
105
|
end
|
93
106
|
end
|
94
107
|
|
data/lib/podio/error.rb
CHANGED
@@ -1,14 +1,20 @@
|
|
1
1
|
module Podio
|
2
|
-
|
3
|
-
|
2
|
+
class PodioError < StandardError
|
3
|
+
attr_reader :response_body, :response_status, :url
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
class ConflictError < PodioError; end
|
11
|
-
class GoneError < PodioError; end
|
12
|
-
class Unavailable < PodioError; end
|
5
|
+
def initialize(response_body, response_status, url)
|
6
|
+
@response_body, @response_status, @url = response_body, response_status, url
|
7
|
+
|
8
|
+
super(response_body.inspect)
|
9
|
+
end
|
13
10
|
end
|
11
|
+
|
12
|
+
class TokenExpired < PodioError; end
|
13
|
+
class AuthorizationError < PodioError; end
|
14
|
+
class BadRequestError < PodioError; end
|
15
|
+
class ServerError < PodioError; end
|
16
|
+
class NotFoundError < PodioError; end
|
17
|
+
class ConflictError < PodioError; end
|
18
|
+
class GoneError < PodioError; end
|
19
|
+
class UnavailableError < PodioError; end
|
14
20
|
end
|
@@ -1,40 +1,37 @@
|
|
1
1
|
module Podio
|
2
2
|
module Middleware
|
3
3
|
class DateConversion < Faraday::Response::Middleware
|
4
|
-
def
|
5
|
-
env[:
|
6
|
-
convert_dates(finished_env[:body]) if finished_env[:body].is_a?(Hash)
|
7
|
-
end
|
4
|
+
def on_complete(env)
|
5
|
+
convert_dates(env[:body]) if env[:body].is_a?(Hash)
|
8
6
|
end
|
9
|
-
|
7
|
+
|
10
8
|
# Converts all attributes ending with "_on" to datetime and ending with "date" to date
|
11
|
-
def
|
9
|
+
def convert_dates(body)
|
12
10
|
[body].flatten.compact.each do |hash|
|
13
11
|
hash.each do |key, value|
|
14
12
|
if value.is_a?(Hash)
|
15
|
-
|
13
|
+
convert_dates(value)
|
16
14
|
elsif value.is_a?(Array)
|
17
|
-
value.each_with_index { |item, index| hash[key][index] =
|
15
|
+
value.each_with_index { |item, index| hash[key][index] = convert_field(key, item) }
|
18
16
|
else
|
19
|
-
hash[key] =
|
17
|
+
hash[key] = convert_field(key, value)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
23
21
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def convert_field(key, value)
|
26
|
+
if key.present?
|
27
|
+
if key[-3..-1] == "_on"
|
28
|
+
return value.try(:to_s).try(:to_datetime)
|
29
|
+
elsif key[-4..-1] == "date"
|
30
|
+
return value.try(:to_s).try(:to_date)
|
34
31
|
end
|
35
|
-
value
|
36
32
|
end
|
37
|
-
|
33
|
+
value
|
34
|
+
end
|
38
35
|
end
|
39
36
|
end
|
40
37
|
end
|
@@ -3,41 +3,35 @@
|
|
3
3
|
module Podio
|
4
4
|
module Middleware
|
5
5
|
class ErrorResponse < Faraday::Response::Middleware
|
6
|
-
def
|
7
|
-
env[:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
raise Error::TokenExpired, finished_env[:body].inspect
|
16
|
-
else
|
17
|
-
raise Error::AuthorizationError, finished_env[:body]
|
18
|
-
end
|
19
|
-
when 403
|
20
|
-
raise Error::AuthorizationError, finished_env[:body]
|
21
|
-
when 404
|
22
|
-
raise Error::NotFoundError, "#{finished_env[:method].to_s.upcase} #{finished_env[:url]}"
|
23
|
-
when 409
|
24
|
-
raise Error::ConflictError, finished_env[:body]
|
25
|
-
when 410
|
26
|
-
raise Error::GoneError, "#{finished_env[:method].to_s.upcase} #{finished_env[:url]}"
|
27
|
-
when 500
|
28
|
-
raise Error::ServerError, finished_env[:body].inspect
|
29
|
-
when 502, 503
|
30
|
-
raise Error::Unavailable, finished_env[:body].inspect
|
6
|
+
def on_complete(env)
|
7
|
+
case env[:status]
|
8
|
+
when 200, 204
|
9
|
+
# pass
|
10
|
+
when 400
|
11
|
+
raise BadRequestError.new(env[:body], env[:status], env[:url])
|
12
|
+
when 401
|
13
|
+
if env[:body]['error_description'] =~ /expired_token/
|
14
|
+
raise TokenExpired.new(env[:body], env[:status], env[:url])
|
31
15
|
else
|
32
|
-
|
33
|
-
|
34
|
-
|
16
|
+
raise AuthorizationError.new(env[:body], env[:status], env[:url])
|
17
|
+
end
|
18
|
+
when 403
|
19
|
+
raise AuthorizationError.new(env[:body], env[:status], env[:url])
|
20
|
+
when 404
|
21
|
+
raise NotFoundError.new(env[:body], env[:status], env[:url])
|
22
|
+
when 409
|
23
|
+
raise ConflictError.new(env[:body], env[:status], env[:url])
|
24
|
+
when 410
|
25
|
+
raise GoneError.new(env[:body], env[:status], env[:url])
|
26
|
+
when 500
|
27
|
+
raise ServerError.new(env[:body], env[:status], env[:url])
|
28
|
+
when 502, 503
|
29
|
+
raise UnavailableError.new(env[:body], env[:status], env[:url])
|
30
|
+
else
|
31
|
+
# anything else is something unexpected, so raise it
|
32
|
+
raise ServerError.new(env[:body], env[:status], env[:url])
|
35
33
|
end
|
36
34
|
end
|
37
|
-
|
38
|
-
def initialize(app)
|
39
|
-
super
|
40
|
-
end
|
41
35
|
end
|
42
36
|
end
|
43
37
|
end
|
@@ -6,24 +6,17 @@ module Podio
|
|
6
6
|
class JsonResponse < Faraday::Response::Middleware
|
7
7
|
require 'multi_json'
|
8
8
|
|
9
|
-
def
|
10
|
-
env[:
|
11
|
-
|
12
|
-
finished_env[:body] = parse(finished_env[:body])
|
13
|
-
end
|
9
|
+
def on_complete(env)
|
10
|
+
if env[:body].is_a?(String) && is_json?(env) && env[:status] < 500
|
11
|
+
env[:body] = parse(env[:body])
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
|
19
|
-
@parser = nil
|
15
|
+
def is_json?(env)
|
16
|
+
env[:response_headers]['content-type'] =~ /application\/json/
|
20
17
|
end
|
21
18
|
|
22
|
-
def
|
23
|
-
finished_env[:response_headers]['content-type'] =~ /application\/json/
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.parse(body)
|
19
|
+
def parse(body)
|
27
20
|
return nil if body !~ /\S/ # json gem doesn't like decoding blank strings
|
28
21
|
MultiJson.decode(body)
|
29
22
|
rescue Object => err
|
@@ -3,13 +3,11 @@ require 'digest/md5'
|
|
3
3
|
module Podio
|
4
4
|
module Middleware
|
5
5
|
class ResponseRecorder < Faraday::Response::Middleware
|
6
|
-
def
|
7
|
-
env[:
|
8
|
-
response = "['#{Faraday::Utils.normalize_path(finished_env[:url])}', :#{finished_env[:method]}, #{finished_env[:status]}, #{finished_env[:response_headers]}, '#{finished_env[:body]}']"
|
6
|
+
def on_complete(env)
|
7
|
+
response = "['#{Faraday::Utils.normalize_path(env[:url])}', :#{env[:method]}, #{env[:status]}, #{env[:response_headers]}, '#{env[:body]}']"
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
9
|
+
filename = Digest::MD5.hexdigest(env[:url].request_uri)
|
10
|
+
File.open("#{filename}.rack", 'w') { |f| f.write(response) }
|
13
11
|
end
|
14
12
|
end
|
15
13
|
end
|
data/lib/podio/version.rb
CHANGED
data/podio.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
16
|
s.require_paths = ['lib']
|
17
17
|
|
18
|
-
s.add_runtime_dependency 'faraday', '~> 0.
|
18
|
+
s.add_runtime_dependency 'faraday', '~> 0.7.0'
|
19
19
|
s.add_runtime_dependency 'activesupport', '~> 3.0'
|
20
20
|
s.add_runtime_dependency 'i18n', '>= 0.4.2'
|
21
21
|
s.add_runtime_dependency 'multi_json', '~> 0.0.5'
|
data/test/client_test.rb
CHANGED
@@ -1,23 +1,15 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class ClientTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
Podio.
|
6
|
-
config.api_url = 'https://api.podio.com'
|
7
|
-
config.api_key = 'client_id'
|
8
|
-
config.api_secret = 'client_secret'
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
test 'should configure defaults' do
|
13
|
-
podio = Podio::Client.new
|
4
|
+
test 'should setup client' do
|
5
|
+
Podio.setup(:api_key => 'client_id', :api_secret => 'client_secret')
|
14
6
|
|
15
|
-
assert_equal
|
16
|
-
assert_equal 'client_id',
|
17
|
-
assert_equal 'client_secret',
|
7
|
+
assert_equal Podio::Client, Podio.client.class
|
8
|
+
assert_equal 'client_id', Podio.client.api_key
|
9
|
+
assert_equal 'client_secret', Podio.client.api_secret
|
18
10
|
end
|
19
11
|
|
20
|
-
test 'should
|
12
|
+
test 'should initialize client' do
|
21
13
|
podio = Podio::Client.new(:api_url => 'https://new.podio.com', :api_key => 'new_client_id', :api_secret => 'new_client_secret')
|
22
14
|
|
23
15
|
assert_equal 'https://new.podio.com', podio.api_url
|
@@ -39,7 +31,7 @@ class ClientTest < Test::Unit::TestCase
|
|
39
31
|
client.oauth_token = nil
|
40
32
|
assert_nil client.oauth_token
|
41
33
|
|
42
|
-
client.
|
34
|
+
client.authenticate_with_credentials('pollas@hoisthq.com', 'secret')
|
43
35
|
|
44
36
|
assert_not_nil client.oauth_token.access_token
|
45
37
|
assert_not_nil client.oauth_token.refresh_token
|
metadata
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: podio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
4
5
|
prerelease:
|
5
|
-
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 0
|
10
|
+
version: 0.4.0
|
6
11
|
platform: ruby
|
7
12
|
authors:
|
8
13
|
- Florian Munz
|
@@ -10,7 +15,7 @@ autorequire:
|
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
17
|
|
13
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-14 00:00:00 +02:00
|
14
19
|
default_executable:
|
15
20
|
dependencies:
|
16
21
|
- !ruby/object:Gem::Dependency
|
@@ -21,7 +26,12 @@ dependencies:
|
|
21
26
|
requirements:
|
22
27
|
- - ~>
|
23
28
|
- !ruby/object:Gem::Version
|
24
|
-
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 7
|
33
|
+
- 0
|
34
|
+
version: 0.7.0
|
25
35
|
type: :runtime
|
26
36
|
version_requirements: *id001
|
27
37
|
- !ruby/object:Gem::Dependency
|
@@ -32,6 +42,10 @@ dependencies:
|
|
32
42
|
requirements:
|
33
43
|
- - ~>
|
34
44
|
- !ruby/object:Gem::Version
|
45
|
+
hash: 7
|
46
|
+
segments:
|
47
|
+
- 3
|
48
|
+
- 0
|
35
49
|
version: "3.0"
|
36
50
|
type: :runtime
|
37
51
|
version_requirements: *id002
|
@@ -43,6 +57,11 @@ dependencies:
|
|
43
57
|
requirements:
|
44
58
|
- - ">="
|
45
59
|
- !ruby/object:Gem::Version
|
60
|
+
hash: 11
|
61
|
+
segments:
|
62
|
+
- 0
|
63
|
+
- 4
|
64
|
+
- 2
|
46
65
|
version: 0.4.2
|
47
66
|
type: :runtime
|
48
67
|
version_requirements: *id003
|
@@ -54,6 +73,11 @@ dependencies:
|
|
54
73
|
requirements:
|
55
74
|
- - ~>
|
56
75
|
- !ruby/object:Gem::Version
|
76
|
+
hash: 21
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
- 0
|
80
|
+
- 5
|
57
81
|
version: 0.0.5
|
58
82
|
type: :runtime
|
59
83
|
version_requirements: *id004
|
@@ -111,19 +135,12 @@ files:
|
|
111
135
|
- lib/podio/middleware/json_response.rb
|
112
136
|
- lib/podio/middleware/logger.rb
|
113
137
|
- lib/podio/middleware/oauth2.rb
|
114
|
-
- lib/podio/middleware/podio_api.rb
|
115
138
|
- lib/podio/middleware/response_recorder.rb
|
116
139
|
- lib/podio/response_wrapper.rb
|
117
140
|
- lib/podio/version.rb
|
118
141
|
- podio.gemspec
|
119
|
-
- test/app_store_test.rb
|
120
142
|
- test/client_test.rb
|
121
|
-
- test/contact_test.rb
|
122
|
-
- test/item_test.rb
|
123
|
-
- test/organization_test.rb
|
124
|
-
- test/space_test.rb
|
125
143
|
- test/test_helper.rb
|
126
|
-
- test/widget_test.rb
|
127
144
|
has_rdoc: true
|
128
145
|
homepage: https://github.com/podio/podio-rb
|
129
146
|
licenses: []
|
@@ -138,26 +155,26 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
155
|
requirements:
|
139
156
|
- - ">="
|
140
157
|
- !ruby/object:Gem::Version
|
158
|
+
hash: 3
|
159
|
+
segments:
|
160
|
+
- 0
|
141
161
|
version: "0"
|
142
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
163
|
none: false
|
144
164
|
requirements:
|
145
165
|
- - ">="
|
146
166
|
- !ruby/object:Gem::Version
|
167
|
+
hash: 3
|
168
|
+
segments:
|
169
|
+
- 0
|
147
170
|
version: "0"
|
148
171
|
requirements: []
|
149
172
|
|
150
173
|
rubyforge_project:
|
151
|
-
rubygems_version: 1.
|
174
|
+
rubygems_version: 1.4.2
|
152
175
|
signing_key:
|
153
176
|
specification_version: 3
|
154
177
|
summary: Ruby wrapper for the Podio API
|
155
178
|
test_files:
|
156
|
-
- test/app_store_test.rb
|
157
179
|
- test/client_test.rb
|
158
|
-
- test/contact_test.rb
|
159
|
-
- test/item_test.rb
|
160
|
-
- test/organization_test.rb
|
161
|
-
- test/space_test.rb
|
162
180
|
- test/test_helper.rb
|
163
|
-
- test/widget_test.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# Fix for Podio API specific weirdnesses
|
2
|
-
#
|
3
|
-
module Podio
|
4
|
-
module Middleware
|
5
|
-
class PodioApi < Faraday::Middleware
|
6
|
-
def call(env)
|
7
|
-
if env[:method] == :post && env[:body].nil?
|
8
|
-
env[:body] = ''
|
9
|
-
end
|
10
|
-
|
11
|
-
@app.call(env)
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(app)
|
15
|
-
super
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/test/app_store_test.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class AppStoreTest < Test::Unit::TestCase
|
4
|
-
test 'should find single category' do
|
5
|
-
category = Podio::Category.find(1)
|
6
|
-
|
7
|
-
assert_equal 1, category['category_id']
|
8
|
-
end
|
9
|
-
|
10
|
-
test 'should find all categories' do
|
11
|
-
categories = Podio::Category.find_all
|
12
|
-
|
13
|
-
assert_equal Array, categories.functional.class
|
14
|
-
assert_not_nil categories.functional.first['category_id']
|
15
|
-
|
16
|
-
assert_equal Array, categories.vertical.class
|
17
|
-
assert_not_nil categories.vertical.first['category_id']
|
18
|
-
end
|
19
|
-
|
20
|
-
test 'should create category' do
|
21
|
-
login_as_user(2)
|
22
|
-
|
23
|
-
status = Podio::Category.create(:type => 'vertical', :name => 'New Category')
|
24
|
-
assert_equal 200, status
|
25
|
-
end
|
26
|
-
|
27
|
-
test 'should update category' do
|
28
|
-
login_as_user(2)
|
29
|
-
|
30
|
-
status = Podio::Category.update(1, :name => 'New name')
|
31
|
-
assert_equal 204, status
|
32
|
-
end
|
33
|
-
|
34
|
-
test 'should delete category' do
|
35
|
-
login_as_user(2)
|
36
|
-
|
37
|
-
status = Podio::Category.delete(3)
|
38
|
-
assert_equal 204, status
|
39
|
-
end
|
40
|
-
end
|
data/test/contact_test.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class ContactTest < Test::Unit::TestCase
|
4
|
-
test 'should find single contact' do
|
5
|
-
contact = Podio::Contact.find(1)
|
6
|
-
|
7
|
-
assert_equal 1, contact['user_id']
|
8
|
-
assert_equal 'King of the API, baby!', contact['about']
|
9
|
-
end
|
10
|
-
|
11
|
-
test 'should find all for org' do
|
12
|
-
contacts = Podio::Contact.find_all_for_org(1)
|
13
|
-
|
14
|
-
assert contacts.size > 0
|
15
|
-
assert_not_nil contacts.first['user_id']
|
16
|
-
end
|
17
|
-
|
18
|
-
test 'should find all for org filtered by key' do
|
19
|
-
contacts = Podio::Contact.find_all_for_org(1, :key => 'organization', :value => 'Hoist')
|
20
|
-
|
21
|
-
assert contacts.size > 0
|
22
|
-
contacts.each do |contact|
|
23
|
-
assert_equal 'Hoist', contact['organization']
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
data/test/item_test.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class ItemTest < Test::Unit::TestCase
|
4
|
-
test 'should find single item' do
|
5
|
-
item = Podio::Item.find(1)
|
6
|
-
|
7
|
-
assert_equal 1, item['item_id']
|
8
|
-
|
9
|
-
assert_equal 1, item['app']['app_id']
|
10
|
-
assert_equal 'Bugs', item['app']['name']
|
11
|
-
end
|
12
|
-
|
13
|
-
test 'should not find nonexistant item' do
|
14
|
-
assert_raises Podio::Error::NotFoundError do
|
15
|
-
Podio::Item.find(42)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
test 'should find items by external id' do
|
20
|
-
items = Podio::Item.find_all_by_external_id(1, 'Bar generator')
|
21
|
-
|
22
|
-
assert items['count'] > 0
|
23
|
-
assert items['total_count'] > 0
|
24
|
-
|
25
|
-
assert items['all'].is_a?(Array)
|
26
|
-
items['all'].each do |item|
|
27
|
-
assert_equal 'Bar generator', item['external_id']
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
test 'should not find anything for nonexistant external ids' do
|
32
|
-
items = Podio::Item.find_all_by_external_id(1, 'Random nonexistant')
|
33
|
-
|
34
|
-
assert_equal [], items['all']
|
35
|
-
assert_equal 0, items['count']
|
36
|
-
end
|
37
|
-
end
|
data/test/organization_test.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class OrganizationTest < Test::Unit::TestCase
|
4
|
-
test 'should find single organization' do
|
5
|
-
org = Podio::Organization.find(1)
|
6
|
-
|
7
|
-
assert_equal 1, org['org_id']
|
8
|
-
assert_equal 'Hoist', org['name']
|
9
|
-
end
|
10
|
-
|
11
|
-
test 'should delete org' do
|
12
|
-
response = Podio::Organization.delete(1)
|
13
|
-
assert_equal 204, response
|
14
|
-
end
|
15
|
-
|
16
|
-
test 'should update org' do
|
17
|
-
response = Podio::Organization.update(1, :name => 'New name')
|
18
|
-
assert_equal 204, response
|
19
|
-
end
|
20
|
-
end
|
data/test/space_test.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class SpaceTest < Test::Unit::TestCase
|
4
|
-
def test_should_find_single_space
|
5
|
-
space = Podio::Space.find(1)
|
6
|
-
|
7
|
-
assert_equal 1, space['space_id']
|
8
|
-
assert_equal 'API', space['name']
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_should_find_all_for_org
|
12
|
-
spaces = Podio::Space.find_all_for_org(1)
|
13
|
-
|
14
|
-
assert spaces.is_a?(Array)
|
15
|
-
assert_not_nil spaces.first['name']
|
16
|
-
end
|
17
|
-
end
|
data/test/widget_test.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class WidgetTest < Test::Unit::TestCase
|
4
|
-
test 'should find single widget' do
|
5
|
-
widget = Podio::Widget.find(1)
|
6
|
-
|
7
|
-
assert_equal 1, widget['widget_id']
|
8
|
-
assert_equal 'State count', widget['title']
|
9
|
-
end
|
10
|
-
|
11
|
-
test 'should find all for reference' do
|
12
|
-
widgets = Podio::Widget.find_all_for_reference(:app, 1)
|
13
|
-
|
14
|
-
assert widgets.is_a?(Array)
|
15
|
-
assert widgets.size > 0
|
16
|
-
end
|
17
|
-
|
18
|
-
test 'should find nothing for reference' do
|
19
|
-
# no widgets exists for this space
|
20
|
-
widgets = Podio::Widget.find_all_for_reference(:space, 2)
|
21
|
-
assert_equal [], widgets
|
22
|
-
end
|
23
|
-
|
24
|
-
test 'should create widget' do
|
25
|
-
response = Podio::Widget.create(:app, 1, {
|
26
|
-
:type => :text,
|
27
|
-
:title => 'widget title',
|
28
|
-
:config => {:text => 'widget'}
|
29
|
-
})
|
30
|
-
|
31
|
-
assert response.is_a?(Integer)
|
32
|
-
end
|
33
|
-
|
34
|
-
test 'should not create widget with missing field' do
|
35
|
-
assert_raises Podio::Error::BadRequestError do
|
36
|
-
Podio::Widget.create(:app, 1, :title => 'widget title', :config => {:text => 'widget'})
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
test 'should update widget' do
|
41
|
-
status = Podio::Widget.update(3, :title => 'Updated title', :config => {:text => 'updated text'})
|
42
|
-
assert_equal 204, status
|
43
|
-
end
|
44
|
-
|
45
|
-
test 'should delete widget' do
|
46
|
-
status = Podio::Widget.delete(1)
|
47
|
-
assert_equal 204, status
|
48
|
-
end
|
49
|
-
|
50
|
-
test 'should update order of widgets' do
|
51
|
-
widgets_ids = Podio::Widget.find_all_for_reference(:space, 1).map { |w| w['widget_id'] }
|
52
|
-
|
53
|
-
Podio::Widget.update_order(:space, 1, widgets_ids.reverse)
|
54
|
-
end
|
55
|
-
end
|