podio 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -4
  4. data/README.md +82 -67
  5. data/lib/podio.rb +15 -2
  6. data/lib/podio/client.rb +11 -7
  7. data/lib/podio/middleware/error_response.rb +3 -1
  8. data/lib/podio/middleware/json_response.rb +6 -1
  9. data/lib/podio/middleware/logger.rb +4 -3
  10. data/lib/podio/middleware/oauth2.rb +5 -5
  11. data/lib/podio/models/answer.rb +8 -0
  12. data/lib/podio/models/app_store_category.rb +2 -2
  13. data/lib/podio/models/app_store_share.rb +1 -0
  14. data/lib/podio/models/application.rb +12 -4
  15. data/lib/podio/models/application_field.rb +10 -0
  16. data/lib/podio/models/batch.rb +1 -0
  17. data/lib/podio/models/calendar_event.rb +6 -5
  18. data/lib/podio/models/campaign.rb +88 -0
  19. data/lib/podio/models/category.rb +1 -1
  20. data/lib/podio/models/contract.rb +18 -20
  21. data/lib/podio/models/contract_attribution.rb +24 -0
  22. data/lib/podio/models/contract_period.rb +22 -0
  23. data/lib/podio/models/contract_price.rb +37 -26
  24. data/lib/podio/models/device.rb +22 -0
  25. data/lib/podio/models/email_subscription_setting.rb +8 -0
  26. data/lib/podio/models/embed.rb +5 -2
  27. data/lib/podio/models/experiment.rb +26 -3
  28. data/lib/podio/models/extension.rb +90 -0
  29. data/lib/podio/models/external_file.rb +3 -3
  30. data/lib/podio/models/file_attachment.rb +25 -2
  31. data/lib/podio/models/form.rb +2 -1
  32. data/lib/podio/models/grant.rb +1 -0
  33. data/lib/podio/models/invoice.rb +13 -0
  34. data/lib/podio/models/item.rb +24 -11
  35. data/lib/podio/models/item_field.rb +6 -0
  36. data/lib/podio/models/item_transaction.rb +34 -0
  37. data/lib/podio/models/live.rb +1 -17
  38. data/lib/podio/models/notification.rb +5 -0
  39. data/lib/podio/models/o_auth.rb +9 -2
  40. data/lib/podio/models/o_auth_client.rb +5 -3
  41. data/lib/podio/models/o_auth_scope.rb +11 -0
  42. data/lib/podio/models/organization.rb +26 -8
  43. data/lib/podio/models/organization_member.rb +6 -0
  44. data/lib/podio/models/organization_membership.rb +15 -0
  45. data/lib/podio/models/profile.rb +2 -0
  46. data/lib/podio/models/promotion.rb +6 -8
  47. data/lib/podio/models/promotion_group.rb +51 -0
  48. data/lib/podio/models/promotion_group_member.rb +32 -0
  49. data/lib/podio/models/rating.rb +4 -2
  50. data/lib/podio/models/reference.rb +2 -1
  51. data/lib/podio/models/space.rb +11 -5
  52. data/lib/podio/models/tag.rb +36 -0
  53. data/lib/podio/models/view.rb +5 -0
  54. data/lib/podio/models/vote.rb +8 -0
  55. data/lib/podio/models/voting.rb +9 -0
  56. data/lib/podio/models/voucher.rb +68 -0
  57. data/lib/podio/version.rb +1 -1
  58. data/podio.gemspec +10 -3
  59. data/test/client_test.rb +14 -0
  60. metadata +31 -13
  61. data/lib/podio/models/contract_price_v2.rb +0 -31
  62. data/lib/podio/models/date_election.rb +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ddca0ab27daadb721f418559e369f9df19ff079b
4
- data.tar.gz: 62879f0a0051374d7edf58585fb23fcdc1b8a65f
3
+ metadata.gz: 8be7a5e8b46cf3874900c1bfb9452ec3319890da
4
+ data.tar.gz: 1ed2281e8019c04a4e44e58afc75e323f183c9d7
5
5
  SHA512:
6
- metadata.gz: 745846890f8a4a11a0ae2591db7d2921ab9fa33cb696b7573aedb7de87c46ddbf4966f16d97132e7da7e13756dff437eb48ae2dff15b34a6e7eed5509fd3550b
7
- data.tar.gz: b1bd3c5b7177185fa91b198f88b05ebd51820c30a4fca4fb00f7f0feab151b2afa3ab2aa013f9881b623ba17eb5db3632be90a302585eeb9263c42a6f0c0297c
6
+ metadata.gz: 330066725f8cd6d4cbafdcc5160b715618ade623cd57ad0aca8b656d8675a79bbf975fa6dba5078d12be2ff50e4756d6f4a7fc9aa7ed4e72f85cc69e95b2d2c7
7
+ data.tar.gz: e3620e6009381f05a79c0524d48c3ef0bc227887f758eb5014bb2820b077601b92d1c121f875b78eb4c6b2eb6b41ea0e0ba0481a3e748a98011ced416ae11b33
data/.gitignore CHANGED
@@ -5,3 +5,4 @@ pkg/*
5
5
  Gemfile.lock
6
6
  script/config.rb
7
7
  *.swp
8
+ .idea
@@ -2,12 +2,9 @@ rvm:
2
2
  - 1.8.7
3
3
  - 1.9.2
4
4
  - 1.9.3
5
- - jruby
5
+ - 2.1
6
6
  - rbx
7
7
  notifications:
8
8
  email:
9
9
  - fabricius@podio.com
10
- - auchenberg@podio.com
11
- - haugstrup@podio.com
12
- - daniel@podio.com
13
10
  - munz@podio.com
data/README.md CHANGED
@@ -17,7 +17,9 @@ Configuration
17
17
 
18
18
  The main way of using the Podio library is via a singleton client, which you set up like this:
19
19
 
20
- Podio.setup(:api_key => 'YOUR_API_KEY', :api_secret => 'YOUR_API_SECRET')
20
+ ```ruby
21
+ Podio.setup(:api_key => 'YOUR_API_KEY', :api_secret => 'YOUR_API_SECRET')
22
+ ```
21
23
 
22
24
  This initializes a `Podio::Client` object and assigns it to a thread-local, which is used by all methods in this library.
23
25
 
@@ -31,58 +33,66 @@ After the configuration you need to authenticate against the API. The client sup
31
33
 
32
34
  The default OAuth flow to be used when you authenticate Podio users from your web application. See the `sinatra.rb` in the examples folder.
33
35
 
34
- # Redirect the user to the authorize url
35
- Podio.client.authorize_url(:redirect_uri => redirect_uri)
36
+ ```ruby
37
+ # Redirect the user to the authorize url
38
+ Podio.client.authorize_url(:redirect_uri => redirect_uri)
36
39
 
37
- # In the callback you get the authorization_code
38
- # wich you use to get the access token
39
- Podio.client.authenticate_with_auth_code(params[:code], redirect_uri)
40
+ # In the callback you get the authorization_code
41
+ # wich you use to get the access token
42
+ Podio.client.authenticate_with_auth_code(params[:code], redirect_uri)
43
+ ```
40
44
 
41
45
  ### Username and Password Flow
42
46
 
43
47
  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.
44
48
 
45
- Podio.client.authenticate_with_credentials('USERNAME', 'PASSWORD')
46
-
49
+ ```ruby
50
+ Podio.client.authenticate_with_credentials('USERNAME', 'PASSWORD')
51
+ ```
47
52
 
48
53
  Basic Usage
49
54
  -----------
50
55
 
51
56
  After you configured the `Podio.client` singleton you can use all of the wrapper functions to do API requests. The functions are organized into models corresponding to the official API documentation, although most API areas have multiple models associated. The method follow a common naming pattern that should be familiar to ActiveRecord users. For example:
52
57
 
53
- # Getting an item
54
- Podio::Item.find(42)
58
+ ```ruby
59
+ # Getting an item
60
+ Podio::Item.find(42)
55
61
 
56
- # Posting a status message on space with id 23
57
- Podio::Status.create(23, {:value => 'This is the text of the status message'})
62
+ # Posting a status message on space with id 23
63
+ Podio::Status.create(23, {:value => 'This is the text of the status message'})
64
+ ```
58
65
 
59
66
  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:
60
67
 
61
- # Getting an item
62
- response = Podio.connection.get('/item/42')
63
- response.body
68
+ ```ruby
69
+ # Getting an item
70
+ response = Podio.connection.get('/item/42')
71
+ response.body
64
72
 
65
- # Posting a status message on space with id 23
66
- response = Podio.connection.post do |req|
67
- req.url '/status/space/23/'
68
- req.body = {:value => 'This is the text of the status message'}
69
- end
70
- response.body
73
+ # Posting a status message on space with id 23
74
+ response = Podio.connection.post do |req|
75
+ req.url '/status/space/23/'
76
+ req.body = {:value => 'This is the text of the status message'}
77
+ end
78
+ response.body
79
+ ```
71
80
 
72
81
  All the wrapped methods either return a single model instance, an array of instances, or a simple Struct in case of pagination:
73
82
 
74
- # Find all items in an app (paginated)
75
- items = Podio::Item.find_all(app_id, :limit => 20)
76
-
77
- # get count of returned items in this call
78
- items.count
83
+ ```ruby
84
+ # Find all items in an app (paginated)
85
+ items = Podio::Item.find_all(app_id, :limit => 20)
79
86
 
80
- # get the returned items in an array
81
- items.all
87
+ # get count of returned items in this call
88
+ items.count
82
89
 
83
- # get count of all items in this app
84
- items.total_count
90
+ # get the returned items in an array
91
+ items.all
85
92
 
93
+ # get count of all items in this app
94
+ items.total_count
95
+ ```
86
96
 
87
97
  Active Podio
88
98
  ------------
@@ -91,61 +101,66 @@ The Podio API is based on REST requests passing JSON back and forth, but we have
91
101
 
92
102
  While the models can be used directly from this gem, we encourage everyone using Podio in a Rails project to add models that extend the standard models:
93
103
 
94
- class Item < Podio::Item # Inherits from the base model in the Podio gem
95
-
96
- # Your custom methods, e.g.:
97
- def application
98
- @app_instance ||= Application.find(self.app_id)
99
- end
100
- end
104
+ ```ruby
105
+ class Item < Podio::Item # Inherits from the base model in the Podio gem
101
106
 
107
+ # Your custom methods, e.g.:
108
+ def application
109
+ @app_instance ||= Application.find(self.app_id)
110
+ end
111
+ end
112
+ ```
102
113
 
103
114
  Error Handling
104
115
  --------------
105
116
 
106
117
  All unsuccessful responses returned by the API (everything that has a 4xx or 5xx HTTP status code) will throw exceptions. All exceptions inherit from `Podio::PodioError` and have three additional properties which give you more information about the error:
107
118
 
108
- begin
109
- Podio::Space.create({:name => 'New Space', :org_id => 42})
110
- rescue Podio::BadRequestError => exc
111
- puts exc.response_body # parsed JSON response from the API
112
- puts exc.response_status # status code of the response
113
- puts exc.url # uri of the API request
119
+ ```ruby
120
+ begin
121
+ Podio::Space.create({:name => 'New Space', :org_id => 42})
122
+ rescue Podio::BadRequestError => exc
123
+ puts exc.response_body # parsed JSON response from the API
124
+ puts exc.response_status # status code of the response
125
+ puts exc.url # uri of the API request
114
126
 
115
- # you normally want this one, a human readable error description
116
- puts exc.message
117
- end
127
+ # you normally want this one, a human readable error description
128
+ puts exc.message
129
+ end
130
+ ```
118
131
 
119
132
  On instance methods, however, exceptions are handled in a way similar to ActiveRecord. These methods returns a boolean indicating if the API request succeeded or not, and makes the code, description and parameters available when the request fails:
120
133
 
121
- @space_contact = SpaceContact.new({:name => 'The Dude', :birthdate => 50.years.ago})
122
- if @space_contact.create
123
- # Success
124
- else
125
- # Error, check:
126
- # @space_contact.error_code
127
- # @space_contact.error_message
128
- # @space_contact.error_parameters
129
- end
130
-
134
+ ```ruby
135
+ @space_contact = SpaceContact.new({:name => 'The Dude', :birthdate => 50.years.ago})
136
+ if @space_contact.create
137
+ # Success
138
+ else
139
+ # Error, check:
140
+ # @space_contact.error_code
141
+ # @space_contact.error_message
142
+ # @space_contact.error_parameters
143
+ end
144
+ ```
131
145
 
132
146
  Full Example
133
147
  ------------
134
148
 
135
- require 'rubygems'
136
- require 'podio'
137
-
138
- Podio.setup(:api_key => 'YOUR_API_KEY', :api_secret => 'YOUR_API_SECRET')
139
- Podio.client.authenticate_with_credentials('YOUR_PODIO_ACCOUNT', 'YOUR_PODIO_PASSWORD')
149
+ ```ruby
150
+ require 'rubygems'
151
+ require 'podio'
140
152
 
141
- # Print a list of organizations I'm a member of
142
- my_orgs = Podio::Organization.find_all
153
+ Podio.setup(:api_key => 'YOUR_API_KEY', :api_secret => 'YOUR_API_SECRET')
154
+ Podio.client.authenticate_with_credentials('YOUR_PODIO_ACCOUNT', 'YOUR_PODIO_PASSWORD')
143
155
 
144
- my_orgs.each do |org|
145
- puts org.name
146
- puts org.url
147
- end
156
+ # Print a list of organizations I'm a member of
157
+ my_orgs = Podio::Organization.find_all
148
158
 
159
+ my_orgs.each do |org|
160
+ puts org.name
161
+ puts org.url
162
+ end
163
+ ```
149
164
 
150
165
  Meta
151
166
  ----
@@ -1,4 +1,5 @@
1
1
  require 'faraday'
2
+ require 'active_support'
2
3
  require 'active_support/core_ext'
3
4
 
4
5
  require 'podio/error'
@@ -69,6 +70,7 @@ module Podio
69
70
  autoload :Action, 'podio/models/action'
70
71
  autoload :ActivationStatus, 'podio/models/activation_status'
71
72
  autoload :Activity, 'podio/models/activity'
73
+ autoload :Answer, 'podio/models/answer'
72
74
  autoload :AppStoreShare, 'podio/models/app_store_share'
73
75
  autoload :AppStoreCategory, 'podio/models/app_store_category'
74
76
  autoload :Application, 'podio/models/application'
@@ -79,6 +81,7 @@ module Podio
79
81
  autoload :ByLine, 'podio/models/by_line'
80
82
  autoload :CalendarEvent, 'podio/models/calendar_event'
81
83
  autoload :CalendarMute, 'podio/models/calendar_mute'
84
+ autoload :Campaign, 'podio/models/campaign'
82
85
  autoload :Category, 'podio/models/category'
83
86
  autoload :Comment, 'podio/models/comment'
84
87
  autoload :Condition, 'podio/models/condition'
@@ -87,19 +90,21 @@ module Podio
87
90
  autoload :Contact, 'podio/models/contact'
88
91
  autoload :Contract, 'podio/models/contract'
89
92
  autoload :ContractAccounting, 'podio/models/contract_accounting'
93
+ autoload :ContractAttribution, 'podio/models/contract_attribution'
90
94
  autoload :ContractEvent, 'podio/models/contract_event'
95
+ autoload :ContractPeriod, 'podio/models/contract_period'
91
96
  autoload :ContractPrice, 'podio/models/contract_price'
92
- autoload :ContractPriceV2, 'podio/models/contract_price_v2'
93
97
  autoload :ContractUser, 'podio/models/contract_user'
94
98
  autoload :Conversation, 'podio/models/conversation'
95
99
  autoload :ConversationEvent, 'podio/models/conversation_event'
96
100
  autoload :ConversationMessage, 'podio/models/conversation_message'
97
101
  autoload :ConversationParticipant, 'podio/models/conversation_participant'
98
- autoload :DateElection, 'podio/models/date_election'
102
+ autoload :Device, 'podio/models/device'
99
103
  autoload :EmailSubscriptionSetting, 'podio/models/email_subscription_setting'
100
104
  autoload :EmailContact, 'podio/models/email_contact'
101
105
  autoload :Embed, 'podio/models/embed'
102
106
  autoload :Experiment, 'podio/models/experiment'
107
+ autoload :Extension, 'podio/models/extension'
103
108
  autoload :ExternalFile, 'podio/models/external_file'
104
109
  autoload :FileAttachment, 'podio/models/file_attachment'
105
110
  autoload :Filter, 'podio/models/filter'
@@ -114,6 +119,7 @@ module Podio
114
119
  autoload :ItemDiff, 'podio/models/item_diff'
115
120
  autoload :ItemField, 'podio/models/item_field'
116
121
  autoload :ItemRevision, 'podio/models/item_revision'
122
+ autoload :ItemTransaction, 'podio/models/item_transaction'
117
123
  autoload :LinkedAccount, 'podio/models/linked_account'
118
124
  autoload :LinkedAccountData, 'podio/models/linked_account_data'
119
125
  autoload :Live, 'podio/models/live'
@@ -122,13 +128,17 @@ module Podio
122
128
  autoload :NotificationGroup, 'podio/models/notification_group'
123
129
  autoload :OAuth, 'podio/models/o_auth'
124
130
  autoload :OAuthClient, 'podio/models/o_auth_client'
131
+ autoload :OAuthScope, 'podio/models/o_auth_scope'
125
132
  autoload :Organization, 'podio/models/organization'
126
133
  autoload :OrganizationContact, 'podio/models/organization_contact'
127
134
  autoload :OrganizationMember, 'podio/models/organization_member'
135
+ autoload :OrganizationMembership, 'podio/models/organization_membership'
128
136
  autoload :OrganizationProfile, 'podio/models/organization_profile'
129
137
  autoload :Pin, 'podio/models/pin'
130
138
  autoload :Profile, 'podio/models/profile'
131
139
  autoload :Promotion, 'podio/models/promotion'
140
+ autoload :PromotionGroup, 'podio/models/promotion_group'
141
+ autoload :PromotionGroupMember, 'podio/models/promotion_group_member'
132
142
  autoload :Question, 'podio/models/question'
133
143
  autoload :QuestionAnswer, 'podio/models/question_answer'
134
144
  autoload :QuestionOption, 'podio/models/question_option'
@@ -156,6 +166,9 @@ module Podio
156
166
  autoload :UserStatus, 'podio/models/user_status'
157
167
  autoload :Via, 'podio/models/via'
158
168
  autoload :View, 'podio/models/view'
169
+ autoload :Vote, 'podio/models/vote'
170
+ autoload :Voting, 'podio/models/voting'
171
+ autoload :Voucher, 'podio/models/voucher'
159
172
  autoload :Widget, 'podio/models/widget'
160
173
 
161
174
  end
@@ -11,6 +11,7 @@ module Podio
11
11
  @oauth_token = options[:oauth_token]
12
12
  @headers = options[:custom_headers] || {}
13
13
  @adapter = options[:adapter] || Faraday.default_adapter
14
+ @request_options = options[:request_options] || {}
14
15
 
15
16
  if options[:enable_stubs]
16
17
  @enable_stubs = true
@@ -52,11 +53,14 @@ module Podio
52
53
  end
53
54
 
54
55
  # Sign in as a user using credentials
55
- def authenticate_with_credentials(username, password)
56
+ def authenticate_with_credentials(username, password, offering_id=nil)
57
+ body = {:grant_type => 'password', :client_id => api_key, :client_secret => api_secret, :username => username, :password => password}
58
+ body[:offering_id] = offering_id if offering_id.present?
59
+
56
60
  response = @oauth_connection.post do |req|
57
61
  req.url '/oauth/token'
58
62
  req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
59
- req.body = {:grant_type => 'password', :client_id => api_key, :client_secret => api_secret, :username => username, :password => password}
63
+ req.body = body
60
64
  end
61
65
 
62
66
  @oauth_token = OAuthToken.new(response.body)
@@ -177,12 +181,12 @@ module Podio
177
181
  end
178
182
 
179
183
  def configure_connection
180
- Faraday::Connection.new(:url => api_url, :headers => configured_headers, :request => {:client => self}) do |builder|
184
+ Faraday::Connection.new(:url => api_url, :headers => configured_headers, :request => @request_options) do |builder|
181
185
  builder.use Middleware::JsonRequest
182
186
  builder.use Faraday::Request::Multipart
183
187
  builder.use Faraday::Request::UrlEncoded
184
- builder.use Middleware::OAuth2
185
- builder.use Middleware::Logger
188
+ builder.use Middleware::OAuth2, :podio_client => self
189
+ builder.use Middleware::Logger, :podio_client => self
186
190
 
187
191
  builder.adapter(*default_adapter)
188
192
 
@@ -198,7 +202,7 @@ module Podio
198
202
 
199
203
  def configure_oauth_connection
200
204
  conn = @connection.dup
201
- conn.options[:client] = self
205
+ conn.options.update(@request_options)
202
206
  conn.headers.delete('authorization')
203
207
  conn.headers.delete('X-Podio-Dry-Run') if @test_mode # oauth requests don't really work well in test mode
204
208
  conn
@@ -206,7 +210,7 @@ module Podio
206
210
 
207
211
  def configure_trusted_connection
208
212
  conn = @connection.dup
209
- conn.options[:client] = self
213
+ conn.options.update(@request_options)
210
214
  conn.headers.delete('authorization')
211
215
  conn.basic_auth(api_key, api_secret)
212
216
  conn
@@ -5,7 +5,9 @@ module Podio
5
5
  class ErrorResponse < Faraday::Response::Middleware
6
6
  def on_complete(env)
7
7
  error_class = case env[:status]
8
- when 200, 204
8
+ when 200, 201, 204
9
+ # pass
10
+ when 304
9
11
  # pass
10
12
  when 400
11
13
  case env[:body]['error']
@@ -7,11 +7,16 @@ module Podio
7
7
  require 'multi_json'
8
8
 
9
9
  def on_complete(env)
10
- if env[:body].is_a?(String) && is_json?(env) && env[:status] != 500
10
+ if env[:body].is_a?(String) && is_json?(env) && should_unmarshal?(env) && env[:status] != 500
11
11
  env[:body] = parse(env[:body])
12
12
  end
13
13
  end
14
14
 
15
+ def should_unmarshal?(env)
16
+ # don't unmarshal data from the API with a content-disposition header.
17
+ not env[:response_headers]['content-disposition'] =~ /filename=/
18
+ end
19
+
15
20
  def is_json?(env)
16
21
  env[:response_headers]['content-type'] =~ /application\/json/
17
22
  end
@@ -7,13 +7,14 @@ module Podio
7
7
  # Preserve request body
8
8
  env[:request_body] = env[:body] if env[:body]
9
9
 
10
- env[:request][:client].log(env) do
10
+ @podio_client.log(env) do
11
11
  @app.call(env)
12
12
  end
13
13
  end
14
14
 
15
- def initialize(app)
16
- super
15
+ def initialize(app, options={})
16
+ super(app)
17
+ @podio_client = options[:podio_client]
17
18
  end
18
19
  end
19
20
  end
@@ -4,16 +4,15 @@ module Podio
4
4
  module Middleware
5
5
  class OAuth2 < Faraday::Middleware
6
6
  def call(env)
7
- podio_client = env[:request][:client]
8
7
  orig_env = env.dup
9
8
 
10
9
  begin
11
10
  @app.call(env)
12
11
  rescue TokenExpired
13
- podio_client.refresh_access_token
12
+ @podio_client.refresh_access_token
14
13
 
15
14
  # new access token needs to be put into the header
16
- orig_env[:request_headers].merge!(podio_client.configured_headers)
15
+ orig_env[:request_headers].merge!(@podio_client.configured_headers)
17
16
 
18
17
  # rewind the body if this was a file upload
19
18
  orig_env[:body].rewind if orig_env[:body].respond_to?(:rewind)
@@ -23,8 +22,9 @@ module Podio
23
22
  end
24
23
  end
25
24
 
26
- def initialize(app)
27
- super
25
+ def initialize(app, options={})
26
+ super(app)
27
+ @podio_client = options[:podio_client]
28
28
  end
29
29
  end
30
30
  end