podio 0.6.0 → 0.7.0
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.
- data/.travis.yml +4 -0
- data/LICENSE +1 -1
- data/lib/podio.rb +7 -3
- data/lib/podio/active_podio/base.rb +121 -54
- data/lib/podio/client.rb +15 -2
- data/lib/podio/error.rb +1 -0
- data/lib/podio/middleware/error_response.rb +2 -0
- data/lib/podio/models/app_store_share.rb +8 -4
- data/lib/podio/models/application.rb +4 -0
- data/lib/podio/models/{calendar.rb → calendar_event.rb} +13 -1
- data/lib/podio/models/contact.rb +1 -0
- data/lib/podio/models/contract.rb +17 -1
- data/lib/podio/models/email_subscription_setting.rb +1 -0
- data/lib/podio/models/external_file.rb +30 -0
- data/lib/podio/models/file_attachment.rb +30 -12
- data/lib/podio/models/filter.rb +33 -2
- data/lib/podio/models/item.rb +23 -0
- data/lib/podio/models/item_field.rb +1 -1
- data/lib/podio/models/linked_account.rb +32 -0
- data/lib/podio/models/meeting.rb +55 -30
- data/lib/podio/models/meeting_participiant.rb +10 -4
- data/lib/podio/models/notification_group.rb +3 -4
- data/lib/podio/models/organization.rb +11 -9
- data/lib/podio/models/organization_member.rb +2 -1
- data/lib/podio/models/organization_profile.rb +1 -0
- data/lib/podio/models/question_answer.rb +3 -2
- data/lib/podio/models/referral.rb +25 -0
- data/lib/podio/models/reminder.rb +2 -2
- data/lib/podio/models/search.rb +34 -5
- data/lib/podio/models/space_invitation.rb +9 -4
- data/lib/podio/models/space_member.rb +8 -0
- data/lib/podio/models/subscription.rb +7 -3
- data/lib/podio/models/user_status.rb +2 -1
- data/lib/podio/models/widget.rb +2 -0
- data/lib/podio/version.rb +1 -1
- data/test/active_podio_test.rb +2 -2
- metadata +14 -11
data/.travis.yml
CHANGED
data/LICENSE
CHANGED
data/lib/podio.rb
CHANGED
@@ -54,18 +54,19 @@ module Podio
|
|
54
54
|
end
|
55
55
|
end
|
56
56
|
|
57
|
-
class OAuthToken < Struct.new(:access_token, :refresh_token, :expires_at, :reference, :refreshed)
|
57
|
+
class OAuthToken < Struct.new(:access_token, :refresh_token, :expires_at, :expires_in, :reference, :refreshed)
|
58
58
|
def initialize(params = {})
|
59
59
|
self.access_token = params['access_token']
|
60
60
|
self.refresh_token = params['refresh_token']
|
61
61
|
self.reference = params['ref']
|
62
62
|
self.expires_at = Time.now + params['expires_in'] if params['expires_in']
|
63
|
+
self.expires_in = params['expires_in'] if params['expires_in']
|
63
64
|
end
|
64
65
|
end
|
65
66
|
|
66
67
|
autoload :Client, 'podio/client'
|
67
68
|
autoload :ResponseWrapper, 'podio/response_wrapper'
|
68
|
-
|
69
|
+
|
69
70
|
autoload :Action, 'podio/models/action'
|
70
71
|
autoload :ActivationStatus, 'podio/models/activation_status'
|
71
72
|
autoload :Activity, 'podio/models/activity'
|
@@ -75,7 +76,7 @@ module Podio
|
|
75
76
|
autoload :ApplicationField, 'podio/models/application_field'
|
76
77
|
autoload :Bulletin, 'podio/models/bulletin'
|
77
78
|
autoload :ByLine, 'podio/models/by_line'
|
78
|
-
autoload :
|
79
|
+
autoload :CalendarEvent, 'podio/models/calendar_event'
|
79
80
|
autoload :CalendarMute, 'podio/models/calendar_mute'
|
80
81
|
autoload :Category, 'podio/models/category'
|
81
82
|
autoload :Comment, 'podio/models/comment'
|
@@ -89,6 +90,7 @@ module Podio
|
|
89
90
|
autoload :ConversationParticipant, 'podio/models/conversation_participant'
|
90
91
|
autoload :EmailSubscriptionSetting, 'podio/models/email_subscription_setting'
|
91
92
|
autoload :Embed, 'podio/models/embed'
|
93
|
+
autoload :ExternalFile, 'podio/models/external_file'
|
92
94
|
autoload :FileAttachment, 'podio/models/file_attachment'
|
93
95
|
autoload :Filter, 'podio/models/filter'
|
94
96
|
autoload :Form, 'podio/models/form'
|
@@ -99,6 +101,7 @@ module Podio
|
|
99
101
|
autoload :ItemDiff, 'podio/models/item_diff'
|
100
102
|
autoload :ItemField, 'podio/models/item_field'
|
101
103
|
autoload :ItemRevision, 'podio/models/item_revision'
|
104
|
+
autoload :LinkedAccount, 'podio/models/linked_account'
|
102
105
|
autoload :Meeting, 'podio/models/meeting'
|
103
106
|
autoload :MeetingParticipant, 'podio/models/meeting_participiant'
|
104
107
|
autoload :News, 'podio/models/news'
|
@@ -116,6 +119,7 @@ module Podio
|
|
116
119
|
autoload :QuestionOption, 'podio/models/question_option'
|
117
120
|
autoload :Rating, 'podio/models/rating'
|
118
121
|
autoload :Recurrence, 'podio/models/recurrence'
|
122
|
+
autoload :Referral, 'podio/models/referral'
|
119
123
|
autoload :Reminder, 'podio/models/reminder'
|
120
124
|
autoload :Search, 'podio/models/search'
|
121
125
|
autoload :Space, 'podio/models/space'
|
@@ -5,8 +5,8 @@ module ActivePodio
|
|
5
5
|
class Base
|
6
6
|
extend ActiveModel::Naming, ActiveModel::Callbacks
|
7
7
|
include ActiveModel::Conversion
|
8
|
-
|
9
|
-
|
8
|
+
|
9
|
+
class_attribute :valid_attributes, :_associations, :_properties
|
10
10
|
attr_accessor :attributes, :error_code, :error_message, :error_parameters, :error_propagate
|
11
11
|
alias_method :propagate_error?, :error_propagate
|
12
12
|
|
@@ -16,12 +16,12 @@ module ActivePodio
|
|
16
16
|
self.attributes = Hash[*self.valid_attributes.collect { |n| [n.to_sym, nil] }.flatten].merge(attributes.symbolize_keys)
|
17
17
|
|
18
18
|
@values_from_api = options[:values_from_api] # Used to determine if date times should be converted from local to utc, or are already utc
|
19
|
-
|
19
|
+
|
20
20
|
attributes.each do |key, value|
|
21
21
|
if self.respond_to?("#{key}=".to_sym)
|
22
22
|
self.send("#{key}=".to_sym, value)
|
23
23
|
else
|
24
|
-
is_association_hash = value.is_a?(Hash) && self.
|
24
|
+
is_association_hash = value.is_a?(Hash) && self._associations.present? && self._associations.has_key?(key.to_sym) && self._associations[key.to_sym] == :has_one && self.send(key.to_sym).respond_to?(:attributes)
|
25
25
|
if valid_attributes.include?(key.to_sym) || is_association_hash
|
26
26
|
# Initialize nested object to get correctly casted values set back, unless the given values are all blank
|
27
27
|
if is_association_hash
|
@@ -40,26 +40,26 @@ module ActivePodio
|
|
40
40
|
@belongs_to = options[:belongs_to] # Allows has_one associations to communicate their changed content back to their parent model
|
41
41
|
@values_from_api = false
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def persisted?
|
45
45
|
! self.new_record?
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def new_record?
|
49
49
|
! (self.respond_to?(:id) && self.id.present?)
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
def to_param
|
53
53
|
local_id = self.id if self.respond_to?(:id)
|
54
54
|
local_id = nil if local_id == self.object_id # Id still returns object_id in Ruby 1.8.7, JRuby and Rubinius
|
55
55
|
local_id.try(:to_s)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
def [](attribute)
|
59
59
|
@attributes ||= {}
|
60
60
|
@attributes[attribute.to_sym]
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
def []=(attribute, value)
|
64
64
|
@attributes ||= {}
|
65
65
|
@attributes[attribute.to_sym] = value
|
@@ -68,22 +68,58 @@ module ActivePodio
|
|
68
68
|
@belongs_to[:model][@belongs_to[:as]][attribute.to_sym] = value
|
69
69
|
end
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
def ==(other)
|
73
73
|
!self.nil? && !other.nil? && self.respond_to?(:id) && other.respond_to?(:id) && self.id == other.id
|
74
74
|
end
|
75
75
|
alias :eql? :==
|
76
|
-
|
76
|
+
|
77
77
|
def hash
|
78
78
|
self.id.hash if self.respond_to?(:id)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
def as_json(options={})
|
82
|
-
|
82
|
+
options ||= {}
|
83
|
+
result = {}
|
84
|
+
result.merge!(:id => self.id) if self.respond_to?(:id)
|
85
|
+
|
86
|
+
if options[:formatted]
|
87
|
+
self.valid_attributes.each do |name|
|
88
|
+
result[name] = json_friendly_value(self.send(name), options)
|
89
|
+
end
|
90
|
+
|
91
|
+
unless options[:nested] == false
|
92
|
+
if self._associations.respond_to?(:each)
|
93
|
+
self._associations.each do |name, type|
|
94
|
+
case type
|
95
|
+
when :has_one
|
96
|
+
result[name] = self.send(name).as_json(options.except(:methods))
|
97
|
+
when :has_many
|
98
|
+
result[name] = self.send(name).collect { |assoc| assoc.as_json(options.except(:methods)) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
else
|
104
|
+
result.merge!(self.attributes)
|
105
|
+
end
|
106
|
+
|
107
|
+
if options[:methods]
|
108
|
+
options[:methods].each do |name|
|
109
|
+
result[name] = json_friendly_value(self.send(name), options)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
result
|
114
|
+
end
|
115
|
+
|
116
|
+
# Override this in models where the class name doesn't match the ref type
|
117
|
+
def api_friendly_ref_type
|
118
|
+
self.class.name.downcase
|
83
119
|
end
|
84
|
-
|
120
|
+
|
85
121
|
private
|
86
|
-
|
122
|
+
|
87
123
|
def klass_for_association(options)
|
88
124
|
klass_name = options[:class]
|
89
125
|
raise "Missing class name of associated model. Provide with :class => 'MyClass'." unless klass_name.present?
|
@@ -95,7 +131,7 @@ module ActivePodio
|
|
95
131
|
end
|
96
132
|
return klass
|
97
133
|
end
|
98
|
-
|
134
|
+
|
99
135
|
def any_values_present_recursive?(values)
|
100
136
|
values.any? do |value|
|
101
137
|
if value.respond_to?(:values)
|
@@ -106,15 +142,28 @@ module ActivePodio
|
|
106
142
|
end
|
107
143
|
end
|
108
144
|
|
145
|
+
def json_friendly_value(ruby_value, options)
|
146
|
+
if options[:formatted]
|
147
|
+
json_value = case ruby_value.class.name
|
148
|
+
when "DateTime", "Time"
|
149
|
+
ruby_value.iso8601
|
150
|
+
else
|
151
|
+
ruby_value
|
152
|
+
end
|
153
|
+
else
|
154
|
+
ruby_value
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
109
158
|
class << self
|
110
|
-
|
159
|
+
|
111
160
|
public
|
112
|
-
|
161
|
+
|
113
162
|
# Defines the the supported attributes of the model
|
114
163
|
def property(name, type = :string, options = {})
|
115
164
|
self.valid_attributes ||= []
|
116
165
|
self.valid_attributes << name
|
117
|
-
|
166
|
+
|
118
167
|
case type
|
119
168
|
when :datetime
|
120
169
|
define_datetime_accessor(name, options)
|
@@ -131,11 +180,11 @@ module ActivePodio
|
|
131
180
|
define_generic_accessor(name)
|
132
181
|
end
|
133
182
|
end
|
134
|
-
|
183
|
+
|
135
184
|
# Wraps a single hash provided from the API in the given model
|
136
185
|
def has_one(name, options = {})
|
137
|
-
self.
|
138
|
-
self.
|
186
|
+
self._associations ||= {}
|
187
|
+
self._associations[name] = :has_one
|
139
188
|
|
140
189
|
self.send(:define_method, name) do
|
141
190
|
klass = klass_for_association(options)
|
@@ -151,12 +200,16 @@ module ActivePodio
|
|
151
200
|
end
|
152
201
|
instance
|
153
202
|
end
|
203
|
+
|
204
|
+
self.send(:define_method, "clear_#{name}") do
|
205
|
+
self.instance_variable_set("@#{name}_has_one_instance", nil)
|
206
|
+
end
|
154
207
|
end
|
155
|
-
|
208
|
+
|
156
209
|
# Wraps a collection of hashes from the API to a collection of the given model
|
157
210
|
def has_many(name, options = {})
|
158
|
-
self.
|
159
|
-
self.
|
211
|
+
self._associations ||= {}
|
212
|
+
self._associations[name] = :has_many
|
160
213
|
|
161
214
|
self.send(:define_method, name) do
|
162
215
|
klass = klass_for_association(options)
|
@@ -172,23 +225,23 @@ module ActivePodio
|
|
172
225
|
end
|
173
226
|
instances
|
174
227
|
end
|
175
|
-
|
228
|
+
|
176
229
|
self.send(:define_method, "#{name}?") do
|
177
230
|
self.send(name).length > 0
|
178
231
|
end
|
179
232
|
end
|
180
|
-
|
233
|
+
|
181
234
|
# Returns a single instance of the model
|
182
235
|
def member(response)
|
183
236
|
new(response, :values_from_api => true)
|
184
237
|
end
|
185
|
-
|
238
|
+
|
186
239
|
# Returns a simple collection model instances
|
187
240
|
def list(response)
|
188
241
|
response.map! { |item| new(item, :values_from_api => true) }
|
189
242
|
response
|
190
243
|
end
|
191
|
-
|
244
|
+
|
192
245
|
# Returns a struct that includes:
|
193
246
|
# * all: A collection model instances
|
194
247
|
# * count: The number of returned records
|
@@ -198,7 +251,7 @@ module ActivePodio
|
|
198
251
|
result.all.map! { |item| new(item, :values_from_api => true) }
|
199
252
|
result
|
200
253
|
end
|
201
|
-
|
254
|
+
|
202
255
|
def delegate_to_hash(hash_name, *attribute_names)
|
203
256
|
options = attribute_names.extract_options!
|
204
257
|
options.reverse_merge!(:prefix => false, :setter => false)
|
@@ -218,7 +271,7 @@ module ActivePodio
|
|
218
271
|
end
|
219
272
|
end
|
220
273
|
end
|
221
|
-
|
274
|
+
|
222
275
|
# Wraps the given methods in a begin/rescue block
|
223
276
|
# If no error occurs, the return value of the method, or true if nil is returned, is returned
|
224
277
|
# If a Podio::PodioError occurs, the method returns false and the error can be read from the error_message accessor
|
@@ -237,7 +290,7 @@ module ActivePodio
|
|
237
290
|
parameters = ex.response_body["error_parameters"]
|
238
291
|
propagate = ex.response_body["error_propagate"]
|
239
292
|
end
|
240
|
-
|
293
|
+
|
241
294
|
if success
|
242
295
|
return result || true
|
243
296
|
else
|
@@ -248,43 +301,46 @@ module ActivePodio
|
|
248
301
|
return false
|
249
302
|
end
|
250
303
|
end
|
251
|
-
|
304
|
+
|
252
305
|
alias_method_chain method_name, :api_errors_handled
|
253
306
|
end
|
254
307
|
end
|
255
|
-
|
308
|
+
|
256
309
|
private
|
257
|
-
|
310
|
+
|
258
311
|
def define_generic_accessor(name, options = {})
|
259
312
|
options.reverse_merge!(:getter => true, :setter => true)
|
260
|
-
|
313
|
+
|
261
314
|
if(options[:getter])
|
262
315
|
self.send(:define_method, name) do
|
263
316
|
self[name.to_sym]
|
264
317
|
end
|
265
318
|
end
|
266
|
-
|
319
|
+
|
267
320
|
if(options[:setter])
|
268
321
|
self.send(:define_method, "#{name}=") do |value|
|
269
322
|
self[name.to_sym] = value
|
270
323
|
end
|
271
324
|
end
|
272
325
|
end
|
273
|
-
|
326
|
+
|
274
327
|
def define_datetime_accessor(name, options = {})
|
275
328
|
self.send(:define_method, name) do
|
276
329
|
options[:convert_timezone] == false ? self[name.to_sym].try(:to_datetime) : self[name.to_sym].try(:to_datetime).try(:in_time_zone)
|
277
330
|
end
|
278
|
-
|
331
|
+
|
279
332
|
self.send(:define_method, "#{name}=") do |value|
|
280
|
-
|
333
|
+
|
281
334
|
# TODO: This should eventually be done on all date times
|
282
335
|
# This option is a temporary fix while API transitions to UTC only
|
283
336
|
if options[:convert_incoming_local_datetime_to_utc] && value.present? && !@values_from_api
|
284
|
-
value =
|
285
|
-
|
337
|
+
value = if value.is_a?(DateTime)
|
338
|
+
Time.zone.local_to_utc(value)
|
339
|
+
else
|
340
|
+
Time.zone.parse(value).try(:utc).try(:to_datetime)
|
341
|
+
end
|
286
342
|
end
|
287
|
-
|
343
|
+
|
288
344
|
self[name.to_sym] = if value.is_a?(DateTime)
|
289
345
|
value.try(:to_s, :db)
|
290
346
|
else
|
@@ -292,12 +348,12 @@ module ActivePodio
|
|
292
348
|
end
|
293
349
|
end
|
294
350
|
end
|
295
|
-
|
351
|
+
|
296
352
|
def define_date_accessor(name)
|
297
353
|
self.send(:define_method, name) do
|
298
354
|
self[name.to_sym].try(:to_date)
|
299
355
|
end
|
300
|
-
|
356
|
+
|
301
357
|
self.send(:define_method, "#{name}=") do |value|
|
302
358
|
self[name.to_sym] = if value.is_a?(Date)
|
303
359
|
value.try(:to_s, :db)
|
@@ -312,7 +368,7 @@ module ActivePodio
|
|
312
368
|
end
|
313
369
|
end
|
314
370
|
end
|
315
|
-
|
371
|
+
|
316
372
|
def define_integer_accessor(name)
|
317
373
|
self.send(:define_method, name) do
|
318
374
|
if self[name.to_sym].present?
|
@@ -321,7 +377,7 @@ module ActivePodio
|
|
321
377
|
nil
|
322
378
|
end
|
323
379
|
end
|
324
|
-
|
380
|
+
|
325
381
|
self.send(:define_method, "#{name}=") do |value|
|
326
382
|
if value.present?
|
327
383
|
self[name.to_sym] = value.to_i
|
@@ -330,7 +386,7 @@ module ActivePodio
|
|
330
386
|
end
|
331
387
|
end
|
332
388
|
end
|
333
|
-
|
389
|
+
|
334
390
|
def define_boolean_accessors(name)
|
335
391
|
self.send(:define_method, "#{name}?") do
|
336
392
|
if self[name.to_sym].present?
|
@@ -339,7 +395,7 @@ module ActivePodio
|
|
339
395
|
nil
|
340
396
|
end
|
341
397
|
end
|
342
|
-
|
398
|
+
|
343
399
|
self.send(:define_method, "#{name}=") do |value|
|
344
400
|
if value == true || value == false
|
345
401
|
self[name.to_sym] = value
|
@@ -350,29 +406,40 @@ module ActivePodio
|
|
350
406
|
end
|
351
407
|
end
|
352
408
|
end
|
353
|
-
|
409
|
+
|
354
410
|
def define_array_accessors(name)
|
355
411
|
unless name.to_s == name.to_s.pluralize
|
356
412
|
self.send(:define_method, name) do
|
357
413
|
self[name.to_sym] || []
|
358
414
|
end
|
359
|
-
|
415
|
+
|
360
416
|
self.send(:define_method, "#{name}=") do |array|
|
361
417
|
self[name.to_sym] = array.respond_to?(:reject) ? array.reject(&:blank?) : array
|
362
418
|
end
|
363
419
|
end
|
364
|
-
|
420
|
+
|
365
421
|
self.send(:define_method, name.to_s.pluralize) do
|
366
422
|
self[name.to_sym] || []
|
367
423
|
end
|
368
|
-
|
424
|
+
|
369
425
|
self.send(:define_method, "#{name.to_s.pluralize}=") do |array|
|
370
426
|
self[name.to_sym] = array.respond_to?(:reject) ? array.reject(&:blank?) : array
|
371
427
|
end
|
372
|
-
|
428
|
+
|
373
429
|
self.send(:define_method, "default_#{name.to_s.singularize}") do
|
374
430
|
self[name.to_sym].try(:first).presence
|
375
431
|
end
|
432
|
+
|
433
|
+
self.send(:define_method, "default_#{name.to_s.singularize}=") do |value|
|
434
|
+
if self[name.to_sym].try(:first).present?
|
435
|
+
self[name.to_sym][0] = value
|
436
|
+
else
|
437
|
+
self[name.to_sym] = [value]
|
438
|
+
end
|
439
|
+
|
440
|
+
self[name.to_sym].compact!
|
441
|
+
|
442
|
+
end
|
376
443
|
end
|
377
444
|
end
|
378
445
|
end
|