podio 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. data/README.md +36 -5
  2. data/Rakefile +3 -1
  3. data/lib/podio/active_podio/base.rb +311 -0
  4. data/lib/podio/active_podio/updatable.rb +22 -0
  5. data/lib/podio/client.rb +7 -4
  6. data/lib/podio/error.rb +1 -0
  7. data/lib/podio/middleware/error_response.rb +5 -1
  8. data/lib/podio/middleware/response_recorder.rb +1 -1
  9. data/lib/podio/models/app_store_share.rb +67 -0
  10. data/lib/podio/{areas → models}/application.rb +23 -7
  11. data/lib/podio/models/application_email.rb +22 -0
  12. data/lib/podio/models/application_field.rb +17 -0
  13. data/lib/podio/{areas → models}/bulletin.rb +16 -5
  14. data/lib/podio/models/by_line.rb +11 -0
  15. data/lib/podio/models/category.rb +49 -0
  16. data/lib/podio/models/comment.rb +63 -0
  17. data/lib/podio/{areas → models}/connection.rb +20 -4
  18. data/lib/podio/models/contact.rb +10 -0
  19. data/lib/podio/models/conversation.rb +72 -0
  20. data/lib/podio/models/conversation_message.rb +12 -0
  21. data/lib/podio/models/conversation_participant.rb +9 -0
  22. data/lib/podio/models/email_subscription_setting.rb +39 -0
  23. data/lib/podio/models/embed.rb +34 -0
  24. data/lib/podio/models/file_attachment.rb +127 -0
  25. data/lib/podio/models/form.rb +25 -0
  26. data/lib/podio/{areas → models}/hook.rb +15 -5
  27. data/lib/podio/{areas → models}/importer.rb +4 -6
  28. data/lib/podio/{areas → models}/integration.rb +40 -4
  29. data/lib/podio/models/item.rb +122 -0
  30. data/lib/podio/models/item_diff.rb +16 -0
  31. data/lib/podio/models/item_field.rb +19 -0
  32. data/lib/podio/models/item_revision.rb +18 -0
  33. data/lib/podio/models/news.rb +83 -0
  34. data/lib/podio/models/notification.rb +47 -0
  35. data/lib/podio/models/notification_group.rb +19 -0
  36. data/lib/podio/models/o_auth.rb +32 -0
  37. data/lib/podio/models/o_auth_client.rb +93 -0
  38. data/lib/podio/{areas → models}/organization.rb +39 -6
  39. data/lib/podio/models/organization_contact.rb +14 -0
  40. data/lib/podio/{areas → models}/organization_member.rb +13 -5
  41. data/lib/podio/models/organization_profile.rb +61 -0
  42. data/lib/podio/{areas/contact.rb → models/profile.rb} +23 -6
  43. data/lib/podio/{areas → models}/rating.rb +5 -7
  44. data/lib/podio/{areas → models}/search.rb +6 -7
  45. data/lib/podio/models/space.rb +45 -0
  46. data/lib/podio/models/space_contact.rb +23 -0
  47. data/lib/podio/models/space_invite.rb +57 -0
  48. data/lib/podio/models/space_member.rb +32 -0
  49. data/lib/podio/models/status.rb +35 -0
  50. data/lib/podio/{areas → models}/subscription.rb +8 -7
  51. data/lib/podio/{areas → models}/tag.rb +14 -7
  52. data/lib/podio/models/task.rb +153 -0
  53. data/lib/podio/models/task_label.rb +50 -0
  54. data/lib/podio/models/user.rb +66 -0
  55. data/lib/podio/models/user_status.rb +18 -0
  56. data/lib/podio/models/via.rb +7 -0
  57. data/lib/podio/{areas → models}/widget.rb +9 -5
  58. data/lib/podio/version.rb +1 -1
  59. data/lib/podio.rb +97 -39
  60. data/podio.gemspec +4 -3
  61. data/test/active_podio_test.rb +256 -0
  62. data/test/client_test.rb +20 -15
  63. data/test/fixtures/client/18a224aaf83ac57a7b8159cecdbb1263.rack +1 -0
  64. data/test/fixtures/client/a87c69a0624af0413a670094c6615651.rack +1 -0
  65. data/test/fixtures/client/ac493997db62308972c208afa76f8479.rack +1 -0
  66. data/test/fixtures/client/d7fbf422c77af768552423633d0389e8.rack +1 -0
  67. data/test/fixtures/client/e2d68afe39f5531195273ea259b63916.rack +1 -0
  68. data/test/fixtures/fixtures.yaml +34 -0
  69. data/test/models_sanity_test.rb +19 -0
  70. data/test/test_helper.rb +22 -28
  71. metadata +89 -64
  72. data/lib/podio/areas/app_store.rb +0 -69
  73. data/lib/podio/areas/comment.rb +0 -36
  74. data/lib/podio/areas/conversation.rb +0 -39
  75. data/lib/podio/areas/email.rb +0 -24
  76. data/lib/podio/areas/file.rb +0 -81
  77. data/lib/podio/areas/form.rb +0 -11
  78. data/lib/podio/areas/item.rb +0 -68
  79. data/lib/podio/areas/notification.rb +0 -39
  80. data/lib/podio/areas/oauth.rb +0 -107
  81. data/lib/podio/areas/organization_profile.rb +0 -32
  82. data/lib/podio/areas/space.rb +0 -77
  83. data/lib/podio/areas/status.rb +0 -19
  84. data/lib/podio/areas/task.rb +0 -108
  85. data/lib/podio/areas/user.rb +0 -31
  86. data/lib/podio/areas/user_status.rb +0 -11
data/README.md CHANGED
@@ -48,7 +48,7 @@ If you're writing a batch job or are just playing around with the API, this is t
48
48
  Basic Usage
49
49
  -----------
50
50
 
51
- 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:
51
+ 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
52
 
53
53
  # Getting an item
54
54
  Podio::Item.find(42)
@@ -69,7 +69,7 @@ If there is a method missing or you want to do something special, you can use th
69
69
  end
70
70
  response.body
71
71
 
72
- All the wrapped methods either return a single Ruby hash, an array of Ruby hashes, or a simple Struct in case of pagination:
72
+ All the wrapped methods either return a single model instance, an array of instances, or a simple Struct in case of pagination:
73
73
 
74
74
  # Find all items in an app (paginated)
75
75
  items = Podio::Item.find_all(app_id, :limit => 20)
@@ -84,10 +84,26 @@ All the wrapped methods either return a single Ruby hash, an array of Ruby hashe
84
84
  items.total_count
85
85
 
86
86
 
87
+ Active Podio
88
+ ------------
89
+
90
+ The Podio API is based on REST requests passing JSON back and forth, but we have tried to make the use of this client an experience more similar to using ActiveRecord from Rails. That means that all find methods return model instances with attributes cast to the expected type (string, integer, boolean, datetime, etc.). Also, models can be instantiated using a params hash, just like with ActiveRecord models.
91
+
92
+ 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
+
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
101
+
102
+
87
103
  Error Handling
88
104
  --------------
89
105
 
90
- 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:
106
+ 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:
91
107
 
92
108
  begin
93
109
  Podio::Space.create({:name => 'New Space', :org_id => 42})
@@ -100,6 +116,18 @@ All unsuccessful responses returned by the API (everything that has a 4xx or 5xx
100
116
  puts exc.response_body['error_description']
101
117
  end
102
118
 
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:
120
+
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
+
103
131
 
104
132
  Full Example
105
133
  ------------
@@ -114,10 +142,13 @@ Full Example
114
142
  my_orgs = Podio::Organization.find_all
115
143
 
116
144
  my_orgs.each do |org|
117
- puts org['name']
118
- puts org['url']
145
+ puts org.name
146
+ puts org.url
119
147
  end
120
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
121
152
 
122
153
  Meta
123
154
  ----
data/Rakefile CHANGED
@@ -7,6 +7,7 @@ Bundler::GemHelper.install_tasks
7
7
  desc 'Run tests'
8
8
  Rake::TestTask.new(:test) do |t|
9
9
  ENV['ENABLE_STUBS'] = 'true'
10
+ ENV['ENABLE_RECORD'] = 'false'
10
11
  t.ruby_opts = ["-rubygems"] if defined? Gem
11
12
  t.libs << "lib" << "test"
12
13
  t.pattern = 'test/**/*_test.rb'
@@ -16,9 +17,10 @@ end
16
17
  desc 'Record responses'
17
18
  task :record do
18
19
  ENV['ENABLE_RECORD'] = 'true'
20
+ ENV['ENABLE_STUBS'] = 'false'
19
21
 
20
22
  Dir['test/**/*_test.rb'].each do |f|
21
- ruby('-Ilib', f)
23
+ ruby("-Ilib:test", f)
22
24
 
23
25
  folder_name = f.match(/test\/(.+)_test.rb/)[1]
24
26
  FileUtils.mkdir_p("test/fixtures/#{folder_name}")
@@ -0,0 +1,311 @@
1
+ require 'active_model'
2
+
3
+ # Extends the Ruby wrapper to behave a bit like ActiveRecord models
4
+ module ActivePodio
5
+ class Base
6
+ extend ActiveModel::Naming, ActiveModel::Callbacks
7
+ include ActiveModel::Conversion
8
+
9
+ class_inheritable_accessor :valid_attributes
10
+ attr_accessor :attributes, :error_code, :error_message, :error_parameters
11
+
12
+ def initialize(attributes = {})
13
+ self.valid_attributes ||= []
14
+ attributes ||= {}
15
+ self.attributes = Hash[*self.valid_attributes.collect { |n| [n.to_sym, nil] }.flatten].merge(attributes.symbolize_keys)
16
+ attributes.each do |key, value|
17
+ if self.respond_to?("#{key}=".to_sym)
18
+ self.send("#{key}=".to_sym, value)
19
+ elsif valid_attributes.include?(key.to_sym)
20
+ self.send(:[]=, key.to_sym, value)
21
+ end
22
+ end
23
+ end
24
+
25
+ def persisted?
26
+ ! self.new_record?
27
+ end
28
+
29
+ def new_record?
30
+ ! (self.respond_to?(:id) && self.id.present?)
31
+ end
32
+
33
+ def to_param
34
+ return self.id.try(:to_s) if self.respond_to?(:id)
35
+ end
36
+
37
+ def [](attribute)
38
+ @attributes ||= {}
39
+ @attributes[attribute.to_sym]
40
+ end
41
+
42
+ def []=(attribute, value)
43
+ @attributes ||= {}
44
+ @attributes[attribute.to_sym] = value
45
+ end
46
+
47
+ def ==(other)
48
+ self.respond_to?(:id) && other.respond_to?(:id) && self.id == other.id
49
+ end
50
+ alias :eql? :==
51
+
52
+ def hash
53
+ self.id.hash if self.respond_to?(:id)
54
+ end
55
+
56
+ def as_json(options={})
57
+ self.attributes
58
+ end
59
+
60
+ private
61
+
62
+ def klass_for_association(options)
63
+ klass_name = options[:class]
64
+ raise "Missing class name of associated model. Provide with :class => 'MyClass'." unless klass_name.present?
65
+ klass = nil
66
+ begin
67
+ klass = klass_name.constantize
68
+ rescue
69
+ klass = "Podio::#{klass_name}".constantize
70
+ end
71
+ return klass
72
+ end
73
+
74
+ class << self
75
+
76
+ public
77
+
78
+ # Defines the the supported attributes of the model
79
+ def property(name, type = :string)
80
+ self.valid_attributes ||= []
81
+ self.valid_attributes << name
82
+
83
+ case type
84
+ when :datetime
85
+ define_datetime_accessor(name)
86
+ when :date
87
+ define_date_accessor(name)
88
+ when :integer
89
+ define_integer_accessor(name)
90
+ when :boolean
91
+ define_generic_accessor(name, :setter => false)
92
+ define_boolean_accessors(name)
93
+ when :array
94
+ define_array_accessors(name)
95
+ else
96
+ define_generic_accessor(name)
97
+ end
98
+ end
99
+
100
+ # Wraps a single hash provided from the API in the given model
101
+ def has_one(name, options = {})
102
+ self.send(:define_method, name) do
103
+ klass = klass_for_association(options)
104
+ instance = self.instance_variable_get("@#{name}_has_one_instance")
105
+ unless instance.present?
106
+ property = options[:property] || name.to_sym
107
+ if self[property].present?
108
+ instance = klass.new(self[property])
109
+ self.instance_variable_set("@#{name}_has_one_instance", instance)
110
+ else
111
+ instance = nil
112
+ end
113
+ end
114
+ instance
115
+ end
116
+ end
117
+
118
+ # Wraps a collection of hashes from the API to a collection of the given model
119
+ def has_many(name, options = {})
120
+ self.send(:define_method, name) do
121
+ klass = klass_for_association(options)
122
+ instances = self.instance_variable_get("@#{name}_has_many_instances")
123
+ unless instances.present?
124
+ property = options[:property] || name.to_sym
125
+ if self[property].present?
126
+ instances = self[property].map { |attributes| klass.new(attributes) }
127
+ self.instance_variable_set("@#{name}_has_many_instances", instances)
128
+ else
129
+ instances = []
130
+ end
131
+ end
132
+ instances
133
+ end
134
+
135
+ self.send(:define_method, "#{name}?") do
136
+ self.send(name).length > 0
137
+ end
138
+ end
139
+
140
+ # Returns a single instance of the model
141
+ def member(response)
142
+ new(response)
143
+ end
144
+
145
+ # Returns a simple collection model instances
146
+ def list(response)
147
+ response.map! { |item| new(item) }
148
+ response
149
+ end
150
+
151
+ # Returns a struct that includes:
152
+ # * all: A collection model instances
153
+ # * count: The number of returned records
154
+ # * total_count: The total number of records matching the given conditions
155
+ def collection(response)
156
+ result = Struct.new(:all, :count, :total_count).new(response['items'], response['filtered'], response['total'])
157
+ result.all.map! { |item| new(item) }
158
+ result
159
+ end
160
+
161
+ def delegate_to_hash(hash_name, *attribute_names)
162
+ attribute_names.each do |attribute_name|
163
+ hash_index = attribute_name.to_s.gsub(/[\?!]/, '')
164
+ self.send(:define_method, attribute_name) do
165
+ self.send(hash_name)[hash_index]
166
+ end
167
+ end
168
+ end
169
+
170
+ # Wraps the given methods in a begin/rescue block
171
+ # If no error occurs, the return value of the method, or true if nil is returned, is returned
172
+ # If a Podio::BadRequestError occurs, the method returns false and the error can be read from the error_message accessor
173
+ # If another error occurs, it is still raised
174
+ def handle_api_errors_for(*method_names)
175
+ method_names.each do |method_name|
176
+ self.send(:define_method, "#{method_name}_with_api_errors_handled") do |*args|
177
+ success, code, message, parameters, result = nil
178
+ begin
179
+ result = self.send("#{method_name}_without_api_errors_handled", *args)
180
+ success = true
181
+ rescue Podio::BadRequestError, Podio::AuthorizationError => ex
182
+ success = false
183
+ code = ex.response_body["error"]
184
+ message = ex.response_body["error_description"]
185
+ parameters = ex.response_body["error_parameters"]
186
+ end
187
+
188
+ if success
189
+ return result || true
190
+ else
191
+ @error_code = code
192
+ @error_message = message
193
+ @error_parameters = parameters
194
+ return false
195
+ end
196
+ end
197
+
198
+ alias_method_chain method_name, :api_errors_handled
199
+ end
200
+ end
201
+
202
+ private
203
+
204
+ def define_generic_accessor(name, options = {})
205
+ options.reverse_merge!(:getter => true, :setter => true)
206
+
207
+ if(options[:getter])
208
+ self.send(:define_method, name) do
209
+ self[name.to_sym]
210
+ end
211
+ end
212
+
213
+ if(options[:setter])
214
+ self.send(:define_method, "#{name}=") do |value|
215
+ self[name.to_sym] = value
216
+ end
217
+ end
218
+ end
219
+
220
+ def define_datetime_accessor(name)
221
+ self.send(:define_method, name) do
222
+ self[name.to_sym].try(:to_datetime).try(:in_time_zone)
223
+ end
224
+
225
+ self.send(:define_method, "#{name}=") do |value|
226
+ self[name.to_sym] = if value.is_a?(DateTime)
227
+ value.try(:to_s, :db)
228
+ else
229
+ value.try(:to_s)
230
+ end
231
+ end
232
+ end
233
+
234
+ def define_date_accessor(name)
235
+ self.send(:define_method, name) do
236
+ self[name.to_sym].try(:to_date)
237
+ end
238
+
239
+ self.send(:define_method, "#{name}=") do |value|
240
+ self[name.to_sym] = if value.is_a?(Date)
241
+ value.try(:to_s, :db)
242
+ else
243
+ value.try(:to_s)
244
+ end
245
+ end
246
+ end
247
+
248
+ def define_integer_accessor(name)
249
+ self.send(:define_method, name) do
250
+ if self[name.to_sym].present?
251
+ self[name.to_sym].to_i
252
+ else
253
+ nil
254
+ end
255
+ end
256
+
257
+ self.send(:define_method, "#{name}=") do |value|
258
+ if value.present?
259
+ self[name.to_sym] = value.to_i
260
+ else
261
+ self[name.to_sym] = nil
262
+ end
263
+ end
264
+ end
265
+
266
+ def define_boolean_accessors(name)
267
+ self.send(:define_method, "#{name}?") do
268
+ if self[name.to_sym].present?
269
+ %w{ true 1 yes }.include?(self[name.to_sym].to_s.strip.downcase)
270
+ else
271
+ nil
272
+ end
273
+ end
274
+
275
+ self.send(:define_method, "#{name}=") do |value|
276
+ if value == true || value == false
277
+ self[name.to_sym] = value
278
+ elsif value.present?
279
+ self[name.to_sym] = %w{ true 1 yes }.include?(value.to_s.strip.downcase)
280
+ else
281
+ self[name.to_sym] = nil
282
+ end
283
+ end
284
+ end
285
+
286
+ def define_array_accessors(name)
287
+ unless name.to_s == name.to_s.pluralize
288
+ self.send(:define_method, name) do
289
+ self[name.to_sym] || []
290
+ end
291
+
292
+ self.send(:define_method, "#{name}=") do |array|
293
+ self[name.to_sym] = array.reject(&:blank?) if array.respond_to?(:reject)
294
+ end
295
+ end
296
+
297
+ self.send(:define_method, name.to_s.pluralize) do
298
+ self[name.to_sym] || []
299
+ end
300
+
301
+ self.send(:define_method, "#{name.to_s.pluralize}=") do |array|
302
+ self[name.to_sym] = array.reject(&:blank?) if array.respond_to?(:reject)
303
+ end
304
+
305
+ self.send(:define_method, "default_#{name.to_s.singularize}") do
306
+ self[name.to_sym].try(:first).presence
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
@@ -0,0 +1,22 @@
1
+ # Adds functionality related to updating to an +ActivePodio+ model
2
+ module ActivePodio
3
+ module Updatable
4
+ extend ActiveSupport::Concern
5
+
6
+ module InstanceMethods
7
+ def update_attributes(attributes)
8
+ attributes.each do |key, value|
9
+ self.send("#{key}=".to_sym, value.presence)
10
+ end
11
+ end
12
+
13
+ def remove_nil_values(input_hash)
14
+ input_hash.inject({}) do |hash, (key, value)|
15
+ hash[key] = value if value.present?
16
+ hash
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
data/lib/podio/client.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Podio
2
2
  class Client
3
- attr_reader :api_url, :api_key, :api_secret, :connection
3
+ attr_reader :api_url, :api_key, :api_secret, :connection, :raw_connection
4
4
  attr_accessor :oauth_token, :stubs, :current_http_client
5
5
 
6
6
  def initialize(options = {})
@@ -95,12 +95,14 @@ module Podio
95
95
 
96
96
  def setup_connections
97
97
  @connection = configure_connection
98
+ @raw_connection = configure_connection(true)
98
99
  @oauth_connection = configure_oauth_connection
99
100
  end
100
101
 
101
- def configure_connection
102
+ def configure_connection(raw=false)
102
103
  Faraday::Connection.new(:url => api_url, :headers => configured_headers, :request => {:client => self}) do |builder|
103
- builder.use Middleware::JsonRequest
104
+ builder.use Middleware::JsonRequest unless raw
105
+ builder.use Faraday::Request::Multipart if raw
104
106
  builder.use Middleware::OAuth2
105
107
  builder.use Middleware::Logger
106
108
 
@@ -109,7 +111,7 @@ module Podio
109
111
  # first response middleware defined get's executed last
110
112
  builder.use Middleware::DateConversion
111
113
  builder.use Middleware::ErrorResponse
112
- builder.use Middleware::JsonResponse
114
+ builder.use Middleware::JsonResponse unless raw
113
115
  builder.use Middleware::ResponseRecorder if @record_mode
114
116
  end
115
117
  end
@@ -128,6 +130,7 @@ module Podio
128
130
 
129
131
  def configure_oauth
130
132
  @connection = configure_connection
133
+ @raw_connection = configure_connection(true)
131
134
  end
132
135
  end
133
136
  end
data/lib/podio/error.rb CHANGED
@@ -10,6 +10,7 @@ module Podio
10
10
  end
11
11
 
12
12
  class TokenExpired < PodioError; end
13
+ class InvalidGrantError < PodioError; end
13
14
  class AuthorizationError < PodioError; end
14
15
  class BadRequestError < PodioError; end
15
16
  class ServerError < PodioError; end
@@ -8,7 +8,11 @@ module Podio
8
8
  when 200, 204
9
9
  # pass
10
10
  when 400
11
- raise BadRequestError.new(env[:body], env[:status], env[:url])
11
+ if env[:body]['error'] == 'invalid_grant'
12
+ raise InvalidGrantError.new(env[:body], env[:status], env[:url])
13
+ else
14
+ raise BadRequestError.new(env[:body], env[:status], env[:url])
15
+ end
12
16
  when 401
13
17
  if env[:body]['error_description'] =~ /expired_token/
14
18
  raise TokenExpired.new(env[:body], env[:status], env[:url])
@@ -7,7 +7,7 @@ module Podio
7
7
  response = "['#{Faraday::Utils.normalize_path(env[:url])}', :#{env[:method]}, #{env[:status]}, #{env[:response_headers]}, '#{env[:body]}']"
8
8
 
9
9
  filename = Digest::MD5.hexdigest(env[:url].request_uri)
10
- File.open("#{filename}.rack", 'w') { |f| f.write(response) }
10
+ ::File.open("#{filename}.rack", 'w') { |f| f.write(response) }
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,67 @@
1
+ class Podio::AppStoreShare < ActivePodio::Base
2
+ property :share_id, :integer
3
+ property :type, :string
4
+ property :status, :string
5
+ property :parents, :hash
6
+ property :name, :string
7
+ property :description, :string
8
+ property :abstract, :string
9
+ property :language, :string
10
+ property :featured, :boolean
11
+ property :features, :array
12
+ property :filters, :array
13
+ property :integration, :string
14
+ property :categories, :hash
15
+ property :org, :hash
16
+ property :author, :hash
17
+ property :author_apps, :integer
18
+ property :author_packs, :integer
19
+ property :icon, :string
20
+ property :comments, :array
21
+ property :ratings, :hash
22
+ property :user_rating, :array
23
+ property :screenshots, :array
24
+ property :info, :hash
25
+
26
+ has_many :children, :class => 'AppStoreShare'
27
+ has_one :author, :class => 'ByLine'
28
+
29
+ alias_method :id, :share_id
30
+
31
+ def create
32
+ self.share_id = self.class.create(self.attributes)
33
+ end
34
+
35
+ def install(space_id, dependencies)
36
+ self.class.install(self.share_id, space_id, dependencies)
37
+ end
38
+
39
+ class << self
40
+ def create(attributes)
41
+ response = Podio.connection.post do |req|
42
+ req.url "/app_store/"
43
+ req.body = attributes
44
+ end
45
+
46
+ response.body['share_id']
47
+ end
48
+
49
+ def install(share_id, space_id, dependencies)
50
+ response = Podio.connection.post do |req|
51
+ req.url "/app_store/#{share_id}/install/v2"
52
+ req.body = {:space_id => space_id, :dependencies => dependencies}
53
+ end
54
+
55
+ response.body
56
+ end
57
+
58
+ def find(id)
59
+ member Podio.connection.get("/app_store/#{id}/v2").body
60
+ end
61
+
62
+ def find_all_private_for_org(org_id)
63
+ list Podio.connection.get("/app_store/org/#{org_id}/").body['shares']
64
+ end
65
+ end
66
+ end
67
+
@@ -1,8 +1,25 @@
1
- module Podio
2
- module Application
3
- include Podio::ResponseWrapper
4
- extend self
5
-
1
+ class Podio::Application < ActivePodio::Base
2
+ property :app_id, :integer
3
+ property :original, :integer
4
+ property :original_revision, :integer
5
+ property :status, :string
6
+ property :icon, :string
7
+ property :space_id, :integer
8
+ property :owner_id, :integer
9
+ property :owner, :hash
10
+ property :config, :hash
11
+ property :fields, :array
12
+ property :subscribed, :boolean
13
+ property :integration, :hash
14
+ property :rights, :array
15
+ property :link, :string
16
+
17
+ has_one :integration, :class => 'Integration'
18
+
19
+ alias_method :id, :app_id
20
+ delegate_to_hash :config, :name, :item_name, :allow_edit?, :allow_attachments?, :allow_comments?, :description
21
+
22
+ class << self
6
23
  def find(app_id)
7
24
  member Podio.connection.get("/app/#{app_id}").body
8
25
  end
@@ -42,7 +59,6 @@ module Podio
42
59
 
43
60
  def delete(id)
44
61
  Podio.connection.delete("/app/#{id}").body
45
- end
46
-
62
+ end
47
63
  end
48
64
  end
@@ -0,0 +1,22 @@
1
+ class Podio::ApplicationEmail < ActivePodio::Base
2
+ include ActivePodio::Updatable
3
+
4
+ property :attachments, :boolean
5
+ property :mappings, :hash
6
+
7
+ class << self
8
+ def get_app_configuration(app_id)
9
+ member Podio.connection.get { |req|
10
+ req.url("/email/app/#{app_id}", {})
11
+ }.body
12
+ end
13
+
14
+ def update_app_configuration(app_id, options)
15
+ Podio.connection.put { |req|
16
+ req.url "/email/app/#{app_id}"
17
+ req.body = options
18
+ }.body
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ class Podio::ApplicationField < ActivePodio::Base
2
+ property :field_id, :integer
3
+ property :type, :string
4
+ property :external_id, :integer
5
+ property :config, :hash
6
+
7
+ alias_method :id, :field_id
8
+ delegate_to_hash :config, :label, :description, :delta, :settings, :required?, :visible?
9
+ delegate_to_hash :settings, :allowed_values, :referenceable_types, :allowed_currencies, :valid_types
10
+
11
+ class << self
12
+ def find(app_id, field_id)
13
+ member Podio.connection.get("/app/#{app_id}/field/#{field_id}").body
14
+ end
15
+
16
+ end
17
+ end
@@ -1,8 +1,18 @@
1
- module Podio
2
- module Bulletin
3
- include Podio::ResponseWrapper
4
- extend self
5
-
1
+ class Podio::Bulletin < ActivePodio::Base
2
+ property :bulletin_id, :integer
3
+ property :title, :string
4
+ property :summary, :string
5
+ property :text, :string
6
+ property :locale, :string
7
+ property :target_group, :string
8
+ property :created_on, :datetime
9
+ property :sent_on, :datetime
10
+
11
+ has_one :created_by, :class => 'ByLine'
12
+
13
+ alias_method :id, :bulletin_id
14
+
15
+ class << self
6
16
  def create(attributes)
7
17
  response = Podio.connection.post do |req|
8
18
  req.url "/bulletin/"
@@ -44,5 +54,6 @@ module Podio
44
54
  def send!(id)
45
55
  Podio.connection.post("/bulletin/#{id}/send").body
46
56
  end
57
+
47
58
  end
48
59
  end