podio 0.8.0 → 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +9 -2
- data/README.md +1 -4
- data/examples/oauth_web_flow/Gemfile +4 -0
- data/examples/{sinatra.rb → oauth_web_flow/sinatra.rb} +7 -6
- data/lib/podio.rb +18 -3
- data/lib/podio/active_podio/base.rb +107 -62
- data/lib/podio/client.rb +30 -5
- data/lib/podio/error.rb +22 -10
- data/lib/podio/middleware/error_response.rb +23 -16
- data/lib/podio/middleware/json_response.rb +1 -1
- data/lib/podio/middleware/logger.rb +3 -0
- data/lib/podio/middleware/oauth2.rb +3 -0
- data/lib/podio/models/account_provider.rb +1 -0
- data/lib/podio/models/action.rb +19 -2
- data/lib/podio/models/activation_status.rb +8 -2
- data/lib/podio/models/app_store_category.rb +4 -1
- data/lib/podio/models/app_store_share.rb +29 -16
- data/lib/podio/models/application.rb +57 -2
- data/lib/podio/models/application_email.rb +5 -2
- data/lib/podio/models/application_field.rb +5 -2
- data/lib/podio/models/batch.rb +8 -0
- data/lib/podio/models/by_line.rb +2 -1
- data/lib/podio/models/calendar_event.rb +63 -3
- data/lib/podio/models/calendar_mute.rb +6 -1
- data/lib/podio/models/category.rb +1 -0
- data/lib/podio/models/comment.rb +29 -8
- data/lib/podio/models/condition.rb +8 -0
- data/lib/podio/models/condition_set.rb +40 -0
- data/lib/podio/models/contact.rb +13 -2
- data/lib/podio/models/contract.rb +85 -1
- data/lib/podio/models/contract_event.rb +17 -0
- data/lib/podio/models/contract_price.rb +3 -7
- data/lib/podio/models/contract_price_v2.rb +31 -0
- data/lib/podio/models/contract_user.rb +4 -0
- data/lib/podio/models/conversation.rb +114 -13
- data/lib/podio/models/conversation_event.rb +51 -0
- data/lib/podio/models/conversation_message.rb +2 -1
- data/lib/podio/models/conversation_participant.rb +3 -2
- data/lib/podio/models/date_election.rb +35 -0
- data/lib/podio/models/email_contact.rb +46 -0
- data/lib/podio/models/email_subscription_setting.rb +4 -23
- data/lib/podio/models/embed.rb +4 -4
- data/lib/podio/models/experiment.rb +71 -0
- data/lib/podio/models/external_file.rb +7 -2
- data/lib/podio/models/file_attachment.rb +23 -0
- data/lib/podio/models/form.rb +7 -0
- data/lib/podio/models/friend.rb +12 -0
- data/lib/podio/models/grant.rb +73 -0
- data/lib/podio/models/hook.rb +13 -6
- data/lib/podio/models/importer.rb +3 -0
- data/lib/podio/models/integration.rb +17 -6
- data/lib/podio/models/invoice.rb +30 -0
- data/lib/podio/models/item.rb +81 -14
- data/lib/podio/models/item_diff.rb +9 -5
- data/lib/podio/models/item_field.rb +11 -2
- data/lib/podio/models/item_revision.rb +5 -2
- data/lib/podio/models/linked_account.rb +1 -0
- data/lib/podio/models/live.rb +61 -0
- data/lib/podio/models/net_promoter_score.rb +28 -0
- data/lib/podio/models/notification.rb +9 -4
- data/lib/podio/models/notification_group.rb +5 -2
- data/lib/podio/models/o_auth.rb +4 -2
- data/lib/podio/models/o_auth_client.rb +1 -2
- data/lib/podio/models/organization.rb +22 -10
- data/lib/podio/models/organization_contact.rb +2 -1
- data/lib/podio/models/organization_member.rb +17 -3
- data/lib/podio/models/organization_profile.rb +8 -2
- data/lib/podio/models/pin.rb +27 -0
- data/lib/podio/models/profile.rb +19 -50
- data/lib/podio/models/promotion.rb +91 -0
- data/lib/podio/models/rating.rb +23 -5
- data/lib/podio/models/recurrence.rb +6 -3
- data/lib/podio/models/reference.rb +17 -1
- data/lib/podio/models/reminder.rb +8 -3
- data/lib/podio/models/search.rb +7 -1
- data/lib/podio/models/space.rb +41 -2
- data/lib/podio/models/space_contact.rb +1 -2
- data/lib/podio/models/space_invitation.rb +4 -5
- data/lib/podio/models/space_member.rb +37 -4
- data/lib/podio/models/status.rb +20 -8
- data/lib/podio/models/stream_activity_group.rb +40 -0
- data/lib/podio/models/stream_mute.rb +7 -8
- data/lib/podio/models/stream_object.rb +19 -11
- data/lib/podio/models/subscription.rb +7 -1
- data/lib/podio/models/tag.rb +6 -1
- data/lib/podio/models/tag_search.rb +2 -1
- data/lib/podio/models/task.rb +74 -18
- data/lib/podio/models/task_label.rb +10 -2
- data/lib/podio/models/user.rb +50 -6
- data/lib/podio/models/user_mail.rb +4 -0
- data/lib/podio/models/user_status.rb +7 -0
- data/lib/podio/models/view.rb +27 -7
- data/lib/podio/models/widget.rb +25 -3
- data/lib/podio/version.rb +1 -1
- data/podio.gemspec +13 -10
- data/script/config.example.rb +6 -0
- data/script/referenceGenerator.rb +87 -0
- data/test/active_podio_test.rb +44 -34
- data/test/client_test.rb +13 -2
- metadata +89 -36
- data/lib/podio/middleware/date_conversion.rb +0 -37
- data/lib/podio/models/bulletin.rb +0 -60
- data/lib/podio/models/connection.rb +0 -53
- data/lib/podio/models/news.rb +0 -85
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: ddca0ab27daadb721f418559e369f9df19ff079b
|
|
4
|
+
data.tar.gz: 62879f0a0051374d7edf58585fb23fcdc1b8a65f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 745846890f8a4a11a0ae2591db7d2921ab9fa33cb696b7573aedb7de87c46ddbf4966f16d97132e7da7e13756dff437eb48ae2dff15b34a6e7eed5509fd3550b
|
|
7
|
+
data.tar.gz: b1bd3c5b7177185fa91b198f88b05ebd51820c30a4fca4fb00f7f0feab151b2afa3ab2aa013f9881b623ba17eb5db3632be90a302585eeb9263c42a6f0c0297c
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -113,7 +113,7 @@ All unsuccessful responses returned by the API (everything that has a 4xx or 5xx
|
|
|
113
113
|
puts exc.url # uri of the API request
|
|
114
114
|
|
|
115
115
|
# you normally want this one, a human readable error description
|
|
116
|
-
puts exc.
|
|
116
|
+
puts exc.message
|
|
117
117
|
end
|
|
118
118
|
|
|
119
119
|
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:
|
|
@@ -146,9 +146,6 @@ Full Example
|
|
|
146
146
|
puts org.url
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
-
Note on Heroku Usage
|
|
150
|
-
--------------------
|
|
151
|
-
If you plan on using podio-rb on Heroku please note that only the 1.9.2 stack has been tested. Specifically, bamboo-mri-1.9.2 is recommended, while 1.8.7 is still stock on Heroku. Refer to their documentation for information on how to migrate your dynos
|
|
152
149
|
|
|
153
150
|
Meta
|
|
154
151
|
----
|
|
@@ -18,11 +18,12 @@ require 'sinatra'
|
|
|
18
18
|
require 'podio'
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
Podio.setup(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
21
|
+
before do
|
|
22
|
+
Podio.setup(
|
|
23
|
+
:api_key => 'YOUR_API_KEY', # CHANGE this this to make this example work
|
|
24
|
+
:api_secret => 'YOUR_API_SECRET' # CHANGE this this to make this example work
|
|
25
|
+
)
|
|
26
|
+
end
|
|
26
27
|
|
|
27
28
|
get '/' do
|
|
28
29
|
%(<p>Update the <code>Podio.setup</code> call in the sinatra app and <a href="/auth/podio">try to authorize</a>.</p>)
|
|
@@ -50,6 +51,6 @@ end
|
|
|
50
51
|
|
|
51
52
|
def redirect_uri(path='/auth/podio/callback')
|
|
52
53
|
uri = URI.parse(request.url)
|
|
53
|
-
uri.path
|
|
54
|
+
uri.path = path
|
|
54
55
|
uri.to_s
|
|
55
56
|
end
|
data/lib/podio.rb
CHANGED
|
@@ -2,8 +2,8 @@ require 'faraday'
|
|
|
2
2
|
require 'active_support/core_ext'
|
|
3
3
|
|
|
4
4
|
require 'podio/error'
|
|
5
|
+
require 'podio/version'
|
|
5
6
|
require 'podio/middleware/json_request'
|
|
6
|
-
#require 'podio/middleware/date_conversion'
|
|
7
7
|
require 'podio/middleware/logger'
|
|
8
8
|
require 'podio/middleware/oauth2'
|
|
9
9
|
require 'podio/middleware/json_response'
|
|
@@ -76,36 +76,48 @@ module Podio
|
|
|
76
76
|
autoload :ApplicationField, 'podio/models/application_field'
|
|
77
77
|
autoload :AccountProvider, 'podio/models/account_provider'
|
|
78
78
|
autoload :Batch, 'podio/models/batch'
|
|
79
|
-
autoload :Bulletin, 'podio/models/bulletin'
|
|
80
79
|
autoload :ByLine, 'podio/models/by_line'
|
|
81
80
|
autoload :CalendarEvent, 'podio/models/calendar_event'
|
|
82
81
|
autoload :CalendarMute, 'podio/models/calendar_mute'
|
|
83
82
|
autoload :Category, 'podio/models/category'
|
|
84
83
|
autoload :Comment, 'podio/models/comment'
|
|
84
|
+
autoload :Condition, 'podio/models/condition'
|
|
85
|
+
autoload :ConditionSet, 'podio/models/condition_set'
|
|
85
86
|
autoload :Connection, 'podio/models/connection'
|
|
86
87
|
autoload :Contact, 'podio/models/contact'
|
|
87
88
|
autoload :Contract, 'podio/models/contract'
|
|
88
89
|
autoload :ContractAccounting, 'podio/models/contract_accounting'
|
|
90
|
+
autoload :ContractEvent, 'podio/models/contract_event'
|
|
89
91
|
autoload :ContractPrice, 'podio/models/contract_price'
|
|
92
|
+
autoload :ContractPriceV2, 'podio/models/contract_price_v2'
|
|
93
|
+
autoload :ContractUser, 'podio/models/contract_user'
|
|
90
94
|
autoload :Conversation, 'podio/models/conversation'
|
|
95
|
+
autoload :ConversationEvent, 'podio/models/conversation_event'
|
|
91
96
|
autoload :ConversationMessage, 'podio/models/conversation_message'
|
|
92
97
|
autoload :ConversationParticipant, 'podio/models/conversation_participant'
|
|
98
|
+
autoload :DateElection, 'podio/models/date_election'
|
|
93
99
|
autoload :EmailSubscriptionSetting, 'podio/models/email_subscription_setting'
|
|
100
|
+
autoload :EmailContact, 'podio/models/email_contact'
|
|
94
101
|
autoload :Embed, 'podio/models/embed'
|
|
102
|
+
autoload :Experiment, 'podio/models/experiment'
|
|
95
103
|
autoload :ExternalFile, 'podio/models/external_file'
|
|
96
104
|
autoload :FileAttachment, 'podio/models/file_attachment'
|
|
97
105
|
autoload :Filter, 'podio/models/filter'
|
|
98
106
|
autoload :Form, 'podio/models/form'
|
|
107
|
+
autoload :Friend, 'podio/models/friend'
|
|
108
|
+
autoload :Grant, 'podio/models/grant'
|
|
99
109
|
autoload :Hook, 'podio/models/hook'
|
|
100
110
|
autoload :Importer, 'podio/models/importer'
|
|
101
111
|
autoload :Integration, 'podio/models/integration'
|
|
112
|
+
autoload :Invoice, 'podio/models/invoice'
|
|
102
113
|
autoload :Item, 'podio/models/item'
|
|
103
114
|
autoload :ItemDiff, 'podio/models/item_diff'
|
|
104
115
|
autoload :ItemField, 'podio/models/item_field'
|
|
105
116
|
autoload :ItemRevision, 'podio/models/item_revision'
|
|
106
117
|
autoload :LinkedAccount, 'podio/models/linked_account'
|
|
107
118
|
autoload :LinkedAccountData, 'podio/models/linked_account_data'
|
|
108
|
-
autoload :
|
|
119
|
+
autoload :Live, 'podio/models/live'
|
|
120
|
+
autoload :NetPromoterScore, 'podio/models/net_promoter_score'
|
|
109
121
|
autoload :Notification, 'podio/models/notification'
|
|
110
122
|
autoload :NotificationGroup, 'podio/models/notification_group'
|
|
111
123
|
autoload :OAuth, 'podio/models/o_auth'
|
|
@@ -114,7 +126,9 @@ module Podio
|
|
|
114
126
|
autoload :OrganizationContact, 'podio/models/organization_contact'
|
|
115
127
|
autoload :OrganizationMember, 'podio/models/organization_member'
|
|
116
128
|
autoload :OrganizationProfile, 'podio/models/organization_profile'
|
|
129
|
+
autoload :Pin, 'podio/models/pin'
|
|
117
130
|
autoload :Profile, 'podio/models/profile'
|
|
131
|
+
autoload :Promotion, 'podio/models/promotion'
|
|
118
132
|
autoload :Question, 'podio/models/question'
|
|
119
133
|
autoload :QuestionAnswer, 'podio/models/question_answer'
|
|
120
134
|
autoload :QuestionOption, 'podio/models/question_option'
|
|
@@ -131,6 +145,7 @@ module Podio
|
|
|
131
145
|
autoload :Status, 'podio/models/status'
|
|
132
146
|
autoload :StreamMute, 'podio/models/stream_mute'
|
|
133
147
|
autoload :StreamObject, 'podio/models/stream_object'
|
|
148
|
+
autoload :StreamActivityGroup, 'podio/models/stream_activity_group'
|
|
134
149
|
autoload :Subscription, 'podio/models/subscription'
|
|
135
150
|
autoload :Tag, 'podio/models/tag'
|
|
136
151
|
autoload :TagSearch, 'podio/models/tag_search'
|
|
@@ -6,12 +6,15 @@ module ActivePodio
|
|
|
6
6
|
extend ActiveModel::Naming, ActiveModel::Callbacks
|
|
7
7
|
include ActiveModel::Conversion
|
|
8
8
|
|
|
9
|
-
class_attribute :valid_attributes, :
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
class_attribute :valid_attributes, :json_attributes, :_associations
|
|
10
|
+
|
|
11
|
+
self.valid_attributes = []
|
|
12
|
+
self.json_attributes = []
|
|
13
|
+
self._associations = {}
|
|
14
|
+
|
|
15
|
+
attr_accessor :attributes
|
|
12
16
|
|
|
13
17
|
def initialize(attributes = {}, options = {})
|
|
14
|
-
self.valid_attributes ||= []
|
|
15
18
|
attributes = {} if attributes.blank?
|
|
16
19
|
self.attributes = Hash[*self.valid_attributes.collect { |n| [n.to_sym, nil] }.flatten].merge(attributes.symbolize_keys)
|
|
17
20
|
|
|
@@ -28,11 +31,20 @@ module ActivePodio
|
|
|
28
31
|
if self.respond_to?("#{key}=".to_sym)
|
|
29
32
|
self.send("#{key}=".to_sym, value)
|
|
30
33
|
else
|
|
31
|
-
is_association_hash = value.is_a?(Hash) && self._associations.
|
|
34
|
+
is_association_hash = value.is_a?(Hash) && self._associations.has_key?(key.to_sym) && self._associations[key.to_sym] == :has_one && (self.send(key.to_sym).respond_to?(:attributes) || self.send(key.to_sym).nil?)
|
|
32
35
|
if valid_attributes.include?(key.to_sym) || is_association_hash
|
|
36
|
+
|
|
33
37
|
# Initialize nested object to get correctly casted values set back, unless the given values are all blank
|
|
34
38
|
if is_association_hash
|
|
35
|
-
|
|
39
|
+
# Merge existing values with given values and do recursive initalize call to get values casted correctly
|
|
40
|
+
if self.send(key.to_sym).present?
|
|
41
|
+
existing_attributes = self.send(key.to_sym).try(:attributes) || {}
|
|
42
|
+
value.reverse_merge!(existing_attributes)
|
|
43
|
+
self.send(key.to_sym).initialize_attributes(value)
|
|
44
|
+
else
|
|
45
|
+
self.send(:[]=, key.to_sym, value)
|
|
46
|
+
end
|
|
47
|
+
|
|
36
48
|
attributes = self.send(key.to_sym).try(:attributes)
|
|
37
49
|
if attributes.present? && any_values_present_recursive?(attributes.values)
|
|
38
50
|
value = attributes
|
|
@@ -68,7 +80,7 @@ module ActivePodio
|
|
|
68
80
|
def []=(attribute, value)
|
|
69
81
|
@attributes ||= {}
|
|
70
82
|
@attributes[attribute.to_sym] = value
|
|
71
|
-
if @belongs_to.present? && value.present?
|
|
83
|
+
if @belongs_to.present? && @belongs_to[:model].present? && @belongs_to[:as].present? && value.present?
|
|
72
84
|
@belongs_to[:model][@belongs_to[:as]] ||= {}
|
|
73
85
|
@belongs_to[:model][@belongs_to[:as]][attribute.to_sym] = value
|
|
74
86
|
end
|
|
@@ -89,18 +101,27 @@ module ActivePodio
|
|
|
89
101
|
result.merge!(:id => self.id) if self.respond_to?(:id)
|
|
90
102
|
|
|
91
103
|
if options[:formatted]
|
|
92
|
-
(self.valid_attributes +
|
|
104
|
+
(self.valid_attributes + self.json_attributes).uniq.each do |name|
|
|
93
105
|
result[name] = json_friendly_value(self.send(name), options)
|
|
94
106
|
end
|
|
95
107
|
|
|
96
108
|
unless options[:nested] == false
|
|
97
|
-
|
|
98
|
-
self.
|
|
109
|
+
self._associations.each do |name, type|
|
|
110
|
+
nested_value = self.send(name)
|
|
111
|
+
unless nested_value.nil?
|
|
112
|
+
nested_options = options.except(:methods)
|
|
113
|
+
if options[:methods].present? && options[:methods].respond_to?(:find)
|
|
114
|
+
methods_hash = options[:methods].find { |method| method.is_a?(Hash) }
|
|
115
|
+
if methods_hash.present?
|
|
116
|
+
nested_methods = methods_hash[name]
|
|
117
|
+
nested_options.merge!(:methods => nested_methods) if nested_methods.present?
|
|
118
|
+
end
|
|
119
|
+
end
|
|
99
120
|
case type
|
|
100
121
|
when :has_one
|
|
101
|
-
result[name] =
|
|
122
|
+
result[name] = nested_value.as_json(nested_options)
|
|
102
123
|
when :has_many
|
|
103
|
-
result[name] =
|
|
124
|
+
result[name] = nested_value.collect { |assoc| assoc.as_json(nested_options) }
|
|
104
125
|
end
|
|
105
126
|
end
|
|
106
127
|
end
|
|
@@ -111,7 +132,7 @@ module ActivePodio
|
|
|
111
132
|
|
|
112
133
|
if options[:methods]
|
|
113
134
|
options[:methods].each do |name|
|
|
114
|
-
result[name] = json_friendly_value(self.send(name), options)
|
|
135
|
+
result[name] = json_friendly_value(self.send(name), options.except(:methods) ) unless name.is_a?(Hash)
|
|
115
136
|
end
|
|
116
137
|
end
|
|
117
138
|
|
|
@@ -120,17 +141,26 @@ module ActivePodio
|
|
|
120
141
|
|
|
121
142
|
# Override this in models where the class name doesn't match the ref type
|
|
122
143
|
def api_friendly_ref_type
|
|
123
|
-
self.class.name.
|
|
144
|
+
self.class.name.demodulize.parameterize
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def parent_model
|
|
148
|
+
@belongs_to[:model] if @belongs_to.present?
|
|
124
149
|
end
|
|
125
150
|
|
|
126
151
|
private
|
|
127
152
|
|
|
128
153
|
def klass_for_association(options)
|
|
129
154
|
klass_name = options[:class]
|
|
155
|
+
|
|
156
|
+
if !klass_name.present? && options[:class_map].present?
|
|
157
|
+
class_property = options[:class_property] || :type
|
|
158
|
+
class_property_value = self.send(class_property).try(:to_sym)
|
|
159
|
+
klass_name = options[:class_map][class_property_value]
|
|
160
|
+
end
|
|
161
|
+
|
|
130
162
|
raise "Missing class name of associated model. Provide with :class => 'MyClass'." unless klass_name.present?
|
|
131
|
-
|
|
132
|
-
klass = "Podio::#{klass_name}".constantize unless klass.respond_to?(:ancestors) && klass.ancestors.include?(ActivePodio::Base)
|
|
133
|
-
return klass
|
|
163
|
+
return self.class.klass_from_string(klass_name)
|
|
134
164
|
end
|
|
135
165
|
|
|
136
166
|
def any_values_present_recursive?(values)
|
|
@@ -145,7 +175,7 @@ module ActivePodio
|
|
|
145
175
|
|
|
146
176
|
def json_friendly_value(ruby_value, options)
|
|
147
177
|
if options[:formatted]
|
|
148
|
-
|
|
178
|
+
case ruby_value.class.name
|
|
149
179
|
when "DateTime", "Time"
|
|
150
180
|
ruby_value.iso8601
|
|
151
181
|
when "Array"
|
|
@@ -153,9 +183,11 @@ module ActivePodio
|
|
|
153
183
|
when "Hash"
|
|
154
184
|
ruby_value.each { |key, value| ruby_value[key] = json_friendly_value(value, options) }
|
|
155
185
|
ruby_value
|
|
186
|
+
when "BigDecimal"
|
|
187
|
+
ruby_value.to_f # No Decimal in Javascript, Float is better than String
|
|
156
188
|
else
|
|
157
189
|
if ruby_value.kind_of?(ActivePodio::Base)
|
|
158
|
-
ruby_value.as_json(options)
|
|
190
|
+
ruby_value.as_json(options.except(:methods))
|
|
159
191
|
else
|
|
160
192
|
ruby_value
|
|
161
193
|
end
|
|
@@ -163,6 +195,7 @@ module ActivePodio
|
|
|
163
195
|
else
|
|
164
196
|
ruby_value
|
|
165
197
|
end
|
|
198
|
+
|
|
166
199
|
end
|
|
167
200
|
|
|
168
201
|
class << self
|
|
@@ -171,8 +204,7 @@ module ActivePodio
|
|
|
171
204
|
|
|
172
205
|
# Defines the the supported attributes of the model
|
|
173
206
|
def property(name, type = :string, options = {})
|
|
174
|
-
self.valid_attributes
|
|
175
|
-
self.valid_attributes << name
|
|
207
|
+
self.valid_attributes += [name]
|
|
176
208
|
|
|
177
209
|
case type
|
|
178
210
|
when :datetime
|
|
@@ -188,6 +220,10 @@ module ActivePodio
|
|
|
188
220
|
define_boolean_accessors(name)
|
|
189
221
|
when :array
|
|
190
222
|
define_array_accessors(name)
|
|
223
|
+
when :float
|
|
224
|
+
define_float_accessor(name)
|
|
225
|
+
when :decimal
|
|
226
|
+
define_decimal_accessor(name)
|
|
191
227
|
else
|
|
192
228
|
define_generic_accessor(name)
|
|
193
229
|
end
|
|
@@ -195,8 +231,7 @@ module ActivePodio
|
|
|
195
231
|
|
|
196
232
|
# Wraps a single hash provided from the API in the given model
|
|
197
233
|
def has_one(name, options = {})
|
|
198
|
-
self._associations
|
|
199
|
-
self._associations[name] = :has_one
|
|
234
|
+
self._associations = self._associations.merge({name => :has_one})
|
|
200
235
|
|
|
201
236
|
self.send(:define_method, name) do
|
|
202
237
|
klass = klass_for_association(options)
|
|
@@ -220,8 +255,7 @@ module ActivePodio
|
|
|
220
255
|
|
|
221
256
|
# Wraps a collection of hashes from the API to a collection of the given model
|
|
222
257
|
def has_many(name, options = {})
|
|
223
|
-
self._associations
|
|
224
|
-
self._associations[name] = :has_many
|
|
258
|
+
self._associations = self._associations.merge({name => :has_many})
|
|
225
259
|
|
|
226
260
|
self.send(:define_method, name) do
|
|
227
261
|
klass = klass_for_association(options)
|
|
@@ -229,7 +263,7 @@ module ActivePodio
|
|
|
229
263
|
unless instances.present?
|
|
230
264
|
property = options[:property] || name.to_sym
|
|
231
265
|
if self[property].present? && self[property].respond_to?(:map)
|
|
232
|
-
instances = self[property].map { |attributes| klass.new(attributes) }
|
|
266
|
+
instances = self[property].map { |attributes| klass.new(attributes, :belongs_to => { :model => self }) }
|
|
233
267
|
self.instance_variable_set("@#{name}_has_many_instances", instances)
|
|
234
268
|
else
|
|
235
269
|
instances = []
|
|
@@ -284,45 +318,16 @@ module ActivePodio
|
|
|
284
318
|
end
|
|
285
319
|
end
|
|
286
320
|
|
|
287
|
-
# Wraps the given methods in a begin/rescue block
|
|
288
|
-
# If no error occurs, the return value of the method, or true if nil is returned, is returned
|
|
289
|
-
# If a Podio::PodioError occurs, the method returns false and the error can be read from the error_message accessor
|
|
290
|
-
# If another error occurs, it is still raised
|
|
291
|
-
def handle_api_errors_for(*method_names)
|
|
292
|
-
method_names.each do |method_name|
|
|
293
|
-
self.send(:define_method, "#{method_name}_with_api_errors_handled") do |*args|
|
|
294
|
-
success, code, message, parameters, result = nil
|
|
295
|
-
begin
|
|
296
|
-
result = self.send("#{method_name}_without_api_errors_handled", *args)
|
|
297
|
-
success = true
|
|
298
|
-
rescue Podio::PodioError => ex
|
|
299
|
-
success = false
|
|
300
|
-
code = ex.response_body["error"]
|
|
301
|
-
message = ex.response_body["error_description"]
|
|
302
|
-
parameters = ex.response_body["error_parameters"]
|
|
303
|
-
propagate = ex.response_body["error_propagate"]
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
if success
|
|
307
|
-
return result || true
|
|
308
|
-
else
|
|
309
|
-
@error_code = code
|
|
310
|
-
@error_message = message
|
|
311
|
-
@error_parameters = parameters || {}
|
|
312
|
-
@error_propagate = propagate
|
|
313
|
-
return false
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
alias_method_chain method_name, :api_errors_handled
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
|
|
321
321
|
def output_attribute_as_json(*attributes)
|
|
322
|
-
self.json_attributes ||= []
|
|
323
322
|
self.json_attributes += attributes
|
|
324
323
|
end
|
|
325
324
|
|
|
325
|
+
def klass_from_string(klass_name)
|
|
326
|
+
klass = klass_name.constantize rescue nil
|
|
327
|
+
klass = "Podio::#{klass_name}".constantize unless klass.respond_to?(:ancestors) && klass.ancestors.include?(ActivePodio::Base)
|
|
328
|
+
return klass
|
|
329
|
+
end
|
|
330
|
+
|
|
326
331
|
private
|
|
327
332
|
|
|
328
333
|
def define_generic_accessor(name, options = {})
|
|
@@ -354,7 +359,11 @@ module ActivePodio
|
|
|
354
359
|
value = if value.is_a?(DateTime)
|
|
355
360
|
Time.zone.local_to_utc(value)
|
|
356
361
|
else
|
|
357
|
-
|
|
362
|
+
begin
|
|
363
|
+
Time.zone.parse(value).try(:utc).try(:to_datetime)
|
|
364
|
+
rescue TZInfo::AmbiguousTime
|
|
365
|
+
nil
|
|
366
|
+
end
|
|
358
367
|
end
|
|
359
368
|
end
|
|
360
369
|
|
|
@@ -419,6 +428,42 @@ module ActivePodio
|
|
|
419
428
|
end
|
|
420
429
|
end
|
|
421
430
|
|
|
431
|
+
def define_float_accessor(name)
|
|
432
|
+
self.send(:define_method, name) do
|
|
433
|
+
if self[name.to_sym].present?
|
|
434
|
+
self[name.to_sym].to_f
|
|
435
|
+
else
|
|
436
|
+
nil
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
self.send(:define_method, "#{name}=") do |value|
|
|
441
|
+
if value.present?
|
|
442
|
+
self[name.to_sym] = value.to_f
|
|
443
|
+
else
|
|
444
|
+
self[name.to_sym] = nil
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def define_decimal_accessor(name)
|
|
450
|
+
self.send(:define_method, name) do
|
|
451
|
+
if self[name.to_sym].present?
|
|
452
|
+
BigDecimal(self[name.to_sym], 2)
|
|
453
|
+
else
|
|
454
|
+
nil
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
self.send(:define_method, "#{name}=") do |value|
|
|
459
|
+
if value.present?
|
|
460
|
+
self[name.to_sym] = BigDecimal(value, 2)
|
|
461
|
+
else
|
|
462
|
+
self[name.to_sym] = nil
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
|
|
422
467
|
def define_boolean_accessors(name)
|
|
423
468
|
self.send(:define_method, "#{name}?") do
|
|
424
469
|
if self[name.to_sym].present?
|