inbox 0.18.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 52b398c61d8967ca093f406987ee2ac503e0f6d9
4
- data.tar.gz: b011b0f946a01c69da854719ecf2802925c05c70
3
+ metadata.gz: 4572727f15af142648617ef23c2d02cfbaeb829a
4
+ data.tar.gz: 11dc0cb420be765146e33679ca143f4ccd798a16
5
5
  SHA512:
6
- metadata.gz: f15355d979d26a67d9bcb06ef646cc0bb7c8009a071372edb68e6c096c652c35b8894f9d6ff70748f3ef3080743c5876633aad7021e0b12da1c3a2a9766c0966
7
- data.tar.gz: 2cf44541f69383d2db41d55441c0fca1dadabee471b5017fc1ad44d7741af26a2fa4382e1b02a9e28b7f725bd54e0ea072cdf72824acb407a9974ffec79a3f8e
6
+ metadata.gz: 37b247c67eeff634a5f215810ea8b60e54a59c49282e0bbab16302b28fd1ac1d808e760891e208f4fd6e35a23228db5a26bf1addbb9c0d0a5c208eaf77dd386c
7
+ data.tar.gz: 573a0525f28d8c219be3df6863846f29b8ee4148b87c7ef9c4f47be79768abb65928c8e9d986b9234c234ec29ece20b608b8a9cf0fc6ec0451bb54544f2222fe
data/README.md CHANGED
@@ -55,7 +55,7 @@ Generally, you should store your App ID and Secret into environment variables to
55
55
 
56
56
  ### Authentication
57
57
 
58
- The Nylas REST API uses server-side (three-legged) OAuth, and the Ruby gem provides convenience methods that simplify the OAuth process. For more information about authenticating with Nylas, visit the [Developer Documentation](https://www.nylas.com/docs/knowledgebase#authentication).
58
+ The Nylas REST API uses server-side (three-legged) OAuth, and the Ruby gem provides convenience methods that simplify the OAuth process. For more information about authenticating with Nylas, visit the [Developer Documentation](https://nylas.com/docs/platform#authentication).
59
59
 
60
60
  **Step 1: Redirect the user to Nylas:**
61
61
 
@@ -113,12 +113,9 @@ If you're using the open-source version of the Nylas Sync Engine or have fewer t
113
113
  ```ruby
114
114
  nylas = Nylas::API.new(config.nylas_app_id, config.nylas_app_secret, nylas_token)
115
115
 
116
- # Get the first namespace
117
- namespace = nylas.namespaces.first
118
-
119
116
  # Print out the email address and provider (Gmail, Exchange)
120
- puts namespace.email_address
121
- puts namespace.provider
117
+ puts nylas.account.email_address
118
+ puts nylas.account.provider
122
119
  ```
123
120
 
124
121
 
@@ -126,36 +123,36 @@ puts namespace.provider
126
123
 
127
124
  ```ruby
128
125
  # Fetch the first thread
129
- thread = namespace.threads.first
126
+ thread = nylas.threads.first
130
127
 
131
128
  # Fetch a specific thread
132
- thread = namespace.threads.find('ac123acd123ef123')
129
+ thread = nylas.threads.find('ac123acd123ef123')
133
130
 
134
131
  # List all threads tagged `inbox`
135
132
  # (paginating 50 at a time until no more are returned.)
136
- namespace.threads.where(:tag => 'inbox').each do |thread|
133
+ nylas.threads.where(:tag => 'inbox').each do |thread|
137
134
  puts thread.subject
138
135
  end
139
136
 
140
137
  # List the 5 most recent unread threads
141
- namespace.threads.where(:tag => 'unread').range(0,4).each do |thread|
138
+ nylas.threads.where(:tag => 'unread').range(0,4).each do |thread|
142
139
  puts thread.subject
143
140
  end
144
141
 
145
142
  # List all threads with 'ben@nylas.com'
146
- namespace.threads.where(:any_email => 'ben@nylas.com').each do |thread|
143
+ nylas.threads.where(:any_email => 'ben@nylas.com').each do |thread|
147
144
  puts thread.subject
148
145
  end
149
146
 
150
147
  # Get number of all threads
151
- count = namespace.threads.count
148
+ count = nylas.threads.count
152
149
 
153
150
  # Get number of threads with 'ben@inboxapp.com'
154
- count = namespace.threads.where(:any_email => 'ben@inboxapp.com').count
151
+ count = nylas.threads.where(:any_email => 'ben@inboxapp.com').count
155
152
 
156
153
  # Collect all threads with 'ben@nylas.com' into an array.
157
154
  # Note: for large numbers of threads, this is not advised.
158
- threads = namespace.threads.where(:any_email => 'ben@nylas.com').all
155
+ threads = nylas.threads.where(:any_email => 'ben@nylas.com').all
159
156
  ```
160
157
 
161
158
 
@@ -181,13 +178,13 @@ thread.update_tags!(tagsToAdd, tagsToRemove)
181
178
  # Add a new label to a message
182
179
 
183
180
  important = nil
184
- ns.labels.each do |label|
181
+ nylas.labels.each do |label|
185
182
  if label.display_name == 'Important'
186
183
  important = label
187
184
  end
188
185
  end
189
186
 
190
- thread = ns.threads.where(:from => "helena@nylas.com").first
187
+ thread = nylas.threads.where(:from => "helena@nylas.com").first
191
188
  thread.labels.push(important)
192
189
  thread.save!
193
190
 
@@ -202,41 +199,41 @@ end
202
199
 
203
200
  ```ruby
204
201
  # List files
205
- namespace.files.each do |file|
202
+ nylas.files.each do |file|
206
203
  puts file.filename
207
204
  end
208
205
 
209
206
  # Create a new file
210
- file = namespace.files.build(:file => File.new("./public/favicon.ico", 'rb'))
207
+ file = nylas.files.build(:file => File.new("./public/favicon.ico", 'rb'))
211
208
  file.save!
212
209
  ```
213
210
 
214
- ### Working with Labels/Folder
211
+ ### Working with Labels/Folders
215
212
 
216
213
  The new folders and labels API replaces the now deprecated Tags API. It allows you to apply Gmail labels to whole threads or individual messages and, for providers other than Gmail, to move threads and messages between folders.
217
214
 
218
215
  ```ruby
219
216
 
220
217
  # List labels
221
- namespace.labels.each do |label|
218
+ nylas.labels.each do |label|
222
219
  puts label.display_name, label.id
223
220
  end
224
221
 
225
222
  # Create a label
226
- label = ns.folders.build(:display_name => 'Test label', :name => 'test name')
223
+ label = nylas.folders.build(:display_name => 'Test label', :name => 'test name')
227
224
  label.save!
228
225
 
229
226
  # Create a folder
230
227
  #
231
228
  # Note that Folders and Labels are absolutely identical from the standpoint of the SDK.
232
229
  # The only difference is that a message can have many labels but only a single folder.
233
- fld = ns.folders.build(:display_name => 'Test folder', :name => 'test name')
230
+ fld = nylas.folders.build(:display_name => 'Test folder', :name => 'test name')
234
231
  fld.save!
235
232
 
236
233
  # Rename a folder
237
234
  #
238
235
  # Note that you can not rename folders like INBOX, Trash, etc.
239
- fld = ns.folders.first
236
+ fld = nylas.folders.first
240
237
  fld.display_name = 'Renamed folder'
241
238
  fld.save!
242
239
 
@@ -247,10 +244,10 @@ fld.save!
247
244
  Each of the primary collections (contacts, messages, etc.) behave the same way as `threads`. For example, finding messages with a filter is similar to finding threads:
248
245
 
249
246
  ```ruby
250
- messages = namespace.messages.where(:to => 'ben@nylas.com`).all
247
+ messages = nylas.messages.where(:to => 'ben@nylas.com`).all
251
248
  ```
252
249
 
253
- The `where` method accepts a hash of filters, as documented in the [Filters Documentation](https://www.nylas.com/docs/api#filters).
250
+ The `where` method accepts a hash of filters, as documented in the [Filters Documentation](https://nylas.com/docs/platform#filters).
254
251
 
255
252
  ### Getting the raw contents of a message
256
253
 
@@ -265,7 +262,7 @@ raw_contents = message.raw
265
262
 
266
263
  ```ruby
267
264
  # Create a new draft
268
- draft = namespace.drafts.build(
265
+ draft = nylas.drafts.build(
269
266
  :to => [{:name => 'Ben Gotow', :email => 'ben@nylas.com'}],
270
267
  :subject => "Sent by Ruby",
271
268
  :body => "Hi there!<strong>This is HTML</strong>"
@@ -288,8 +285,8 @@ draft.send!
288
285
 
289
286
  ````ruby
290
287
  # Every event is attached to a calendar -- get the id of the first calendar
291
- calendar_id = inbox.namespaces.first.calendars.first.id
292
- new_event = inbox.namespaces.first.events.build(:calendar_id => calendar_id, :title => 'Coffee?')
288
+ calendar_id = nylas.calendars.first.id
289
+ new_event = nylas.events.build(:calendar_id => calendar_id, :title => 'Coffee?')
293
290
 
294
291
  # Modify attributes as necessary
295
292
  new_event.location = "L'excelsior"
@@ -310,17 +307,16 @@ emailed_invite.rsvp!(status='yes', comment='I will come')
310
307
 
311
308
  ## Using the Delta sync API
312
309
 
313
- The delta sync API allows fetching all the changes that occured since a specified time. [Read this](https://nylas.com/docs/api#sync-protocol) for more details about the API.
310
+ The delta sync API allows fetching all the changes that occured after a specific time. [Read this](https://nylas.com/docs/platform/#deltas) for more details about the API.
314
311
 
315
312
  ````ruby
316
- # Get all the messages starting from timestamp
317
- #
318
- # we first need to get a cursor object a cursor is simply the id of
319
- # an individual change.
320
- cursor = nylas.namespaces.first.get_cursor(1407543195)
313
+ # Get an API cursor. Cursors are API objects identifying an individual change.
314
+ # The latest cursor is the id of the latest change which was applied
315
+ # to an API object (e.g: a message got read, an event got created, etc.)
316
+ cursor = nylas.latest_cursor
321
317
 
322
318
  last_cursor = nil
323
- nylas.namespaces.first.deltas(cursor) do |event, object|
319
+ nylas.deltas(cursor) do |event, object|
324
320
  if event == "create" or event == "modify"
325
321
  if object.is_a?(Nylas::Contact)
326
322
  puts "#{object.name} - #{object.email}"
@@ -346,14 +342,10 @@ save_to_db(last_cursor)
346
342
  The streaming API will receive deltas in real time, without needing to repeatedly poll. It uses EventMachine for async IO.
347
343
 
348
344
  ````ruby
349
- # Get all the messages starting from timestamp
350
- #
351
- # we first need to get a cursor object a cursor is simply the id of
352
- # an individual change.
353
- cursor = inbox.namespaces.first.get_cursor(1407543195)
345
+ cursor = nylas.latest_cursor
354
346
 
355
347
  last_cursor = nil
356
- inbox.namespaces.first.delta_stream(cursor) do |event, object|
348
+ nylas.delta_stream(cursor) do |event, object|
357
349
  if event == "create" or event == "modify"
358
350
  if object.is_a?(Inbox::Contact)
359
351
  puts "#{object.name} - #{object.email}"
@@ -376,11 +368,11 @@ end
376
368
 
377
369
  ### Exclude changes from a specific type --- get only messages
378
370
  ````ruby
379
- nylas.namespaces.first.deltas(cursor, exclude=[Nylas::Contact,
380
- Nylas::Event,
381
- Nylas::File,
382
- Nylas::Tag,
383
- Nylas::Thread]) do |event, object|
371
+ nylas.deltas(cursor, exclude=[Nylas::Contact,
372
+ Nylas::Event,
373
+ Nylas::File,
374
+ Nylas::Tag,
375
+ Nylas::Thread]) do |event, object|
384
376
  if event == 'create' or event == 'modify'
385
377
  puts object.subject
386
378
  end
@@ -410,11 +402,19 @@ Code | Error Type | Description
410
402
 
411
403
  ## Open-Source Sync Engine
412
404
 
413
- The [Nylas Sync Engine](http://github.com/nylas/sync-engine) is open source, and you can also use the Ruby gem with the open source API. Since the open source API provides no authentication or security, connecting to it is simple. When you instantiate the Nylas object, provide `nil` for the App ID, App Secret, and API Token, and pass the fully-qualified address to your copy of the sync engine:
405
+ The [Nylas Sync Engine](http://github.com/nylas/sync-engine) is open source, and you can also use the Ruby gem with the open source API. Since the open source API provides no authentication or security, connecting to it is simple. When you instantiate the Nylas object, provide `nil` for the App ID and App Secret, and set the API Token to the id of the account you're going to access. Finally, don't forget to pass the fully-qualified address to your copy of the sync engine:
414
406
 
415
407
  ```ruby
416
- require 'inbox'
417
- inbox = Nylas::API.new(nil, nil, nil, 'http://localhost:5555/')
408
+ require 'nylas'
409
+ nylas = Nylas::API.new(nil, nil, nil, 'http://localhost:5555/')
410
+
411
+ # Get the id of the first account -- this is the access token we're
412
+ # going to use.
413
+ account_id = nylas.accounts.first.id
414
+
415
+ # Display the contents of the first message for the first account
416
+ nylas = Nylas::API.new(nil, nil, account_id, 'http://localhost:5555/')
417
+ puts nylas.messages.first.contents
418
418
  ```
419
419
 
420
420
 
@@ -443,10 +443,10 @@ Test your new version (found in `pkg/`) locally, and then release with:
443
443
 
444
444
  If it's your first time updating the ruby gems, you may be prompted for the username/password for rubygems.org. Members of the Nylas team can find that by doing `fetch-password rubygems`.
445
445
 
446
- ## OAuth self-test
447
-
448
- Because it's very important that we don't break OAuth, we require releasers to run the OAuth self-test before releasing a version of the gem. The self-test is a small sinatra program which will ask you to click on a couple URLs. You need to make sure that following the URLs returns a working token.
446
+ ## API self-tests
449
447
 
450
- To set up the program, you need to copy `tests/credentials.rb.templates` as `test/credentials.rb` and edit the `APP_ID` and `APP_SECRET` with a working Nylas API app id and secret. You also need to set up a `/callback` URL in the Nylas admin panel.
448
+ Because it's critical that we don't break the SDK for our customers, we require releasers to run some tests before releasing a new version of the gem. The test programs are located in the test/ directory. To set up them up, you'll need to copy `tests/credentials.rb.templates` as `test/credentials.rb` and edit the `APP_ID` and `APP_SECRET` with a working Nylas API app id and secret. You also need to set up a `/callback` URL in the Nylas admin panel.
451
449
 
452
- You can then run the program using `cd tests && ruby -I../lib auth.rb`
450
+ You can run the programs like this:
451
+ `cd tests && ruby -I../lib auth.rb`
452
+ `cd tests && ruby -I../lib system.rb`
@@ -12,7 +12,7 @@ module Inbox
12
12
  def _perform_account_action!(action)
13
13
  raise UnexpectedAccountAction.new unless action == "upgrade" || action == "downgrade"
14
14
 
15
- collection = ManagementModelCollection.new(Account, @_api, @namespace_id, {:account_id=>@account_id})
15
+ collection = ManagementModelCollection.new(Account, @_api, {:account_id=>@account_id})
16
16
  ::RestClient.post("#{collection.url}/#{@account_id}/#{action}",{}) do |response, request, result|
17
17
  # Throw any exceptions
18
18
  json = Inbox.interpret_response(result, response, :expected_class => Object)
@@ -0,0 +1,21 @@
1
+ # api_account.rb --- functions related to the /account endpoint.
2
+ # not to be confused with account.rb which is used by the hosted API
3
+ # account management endpoint.
4
+ require 'restful_model'
5
+
6
+ module Inbox
7
+ class APIAccount < RestfulModel
8
+
9
+ parameter :account_id
10
+ parameter :email_address
11
+ parameter :id
12
+ parameter :name
13
+ parameter :object
14
+ parameter :organization_unit
15
+ parameter :provider
16
+
17
+ def self.collection_name
18
+ "accounts"
19
+ end
20
+ end
21
+ end
@@ -22,7 +22,7 @@ module Inbox
22
22
  end
23
23
 
24
24
  def send!
25
- url = @_api.url_for_path("/n/#{@namespace_id}/send")
25
+ url = @_api.url_for_path("/send")
26
26
  if @id
27
27
  data = {:draft_id => @id, :version => @version}
28
28
  else
@@ -31,7 +31,7 @@ module Inbox
31
31
  end
32
32
 
33
33
  def rsvp!(status, comment)
34
- url = @_api.url_for_path("/n/#{@namespace_id}/send-rsvp")
34
+ url = @_api.url_for_path("/send-rsvp")
35
35
  data = {:event_id => @id, :status => status, :comment => comment}
36
36
 
37
37
  ::RestClient.post(url, data.to_json, :content_type => :json) do |response, request, result|
@@ -1,9 +1,26 @@
1
- require 'version'
2
- require 'rest-client'
3
- require 'restful_model_collection'
4
1
  require 'json'
5
- require 'namespace'
2
+ require 'rest-client'
3
+ require 'yajl'
4
+ require 'em-http'
5
+ require 'ostruct'
6
+
7
+ require 'account'
8
+ require 'api_account'
9
+ require 'api_thread'
10
+ require 'calendar'
6
11
  require 'account'
12
+ require 'tag'
13
+ require 'message'
14
+ require 'draft'
15
+ require 'contact'
16
+ require 'file'
17
+ require 'calendar'
18
+ require 'event'
19
+ require 'folder'
20
+ require 'restful_model'
21
+ require 'restful_model_collection'
22
+ require 'version'
23
+
7
24
 
8
25
  module Inbox
9
26
 
@@ -122,18 +139,218 @@ module Inbox
122
139
  end
123
140
  end
124
141
 
125
- # Convenience Methods
142
+ # API Methods
143
+ def threads
144
+ @threads ||= RestfulModelCollection.new(Thread, self)
145
+ end
126
146
 
127
- def namespaces
128
- @namespaces ||= RestfulModelCollection.new(Namespace, self, nil)
129
- @namespaces
147
+ def tags
148
+ @tags ||= RestfulModelCollection.new(Tag, self)
130
149
  end
131
150
 
132
- # Billing Methods
151
+ def messages
152
+ @messages ||= RestfulModelCollection.new(Message, self)
153
+ end
154
+
155
+ def files
156
+ @files ||= RestfulModelCollection.new(File, self)
157
+ end
158
+
159
+ def drafts
160
+ @drafts ||= RestfulModelCollection.new(Draft, self)
161
+ end
162
+
163
+ def contacts
164
+ @contacts ||= RestfulModelCollection.new(Contact, self)
165
+ end
166
+
167
+ def calendars
168
+ @calendars ||= RestfulModelCollection.new(Calendar, self)
169
+ end
170
+
171
+ def events
172
+ @events ||= RestfulModelCollection.new(Event, self)
173
+ end
174
+
175
+ def folders
176
+ @folders ||= RestfulModelCollection.new(Folder, self)
177
+ end
178
+
179
+ def labels
180
+ @labels ||= RestfulModelCollection.new(Label, self)
181
+ end
182
+
183
+ def account
184
+ path = self.url_for_path("/account")
185
+
186
+ RestClient.get(path, {}) do |response,request,result|
187
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
188
+ model = APIAccount.new(self)
189
+ model.inflate(json)
190
+ model
191
+ end
192
+ end
193
+
194
+ def using_hosted_api?
195
+ return !@app_id.nil?
196
+ end
133
197
 
134
198
  def accounts
135
- @accounts ||= ManagementModelCollection.new(Account, self, nil)
136
- @accounts
199
+ if self.using_hosted_api?
200
+ @accounts ||= ManagementModelCollection.new(Account, self)
201
+ else
202
+ @accounts ||= RestfulModelCollection.new(APIAccount, self)
203
+ end
204
+ end
205
+
206
+ def get_cursor(timestamp)
207
+ # Get the cursor corresponding to a specific timestamp.
208
+ warn "Nylas#get_cursor is deprecated. Use Nylas#latest_cursor instead."
209
+
210
+ path = self.url_for_path("/delta/generate_cursor")
211
+ data = { :start => timestamp }
212
+
213
+ cursor = nil
214
+
215
+ RestClient.post(path, data.to_json, :content_type => :json) do |response,request,result|
216
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
217
+ cursor = json["cursor"]
218
+ end
219
+
220
+ cursor
221
+ end
222
+
223
+ def latest_cursor
224
+ # Get the cursor corresponding to a specific timestamp.
225
+ path = self.url_for_path("/delta/latest_cursor")
226
+
227
+ cursor = nil
228
+
229
+ RestClient.post(path, :content_type => :json) do |response,request,result|
230
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
231
+ cursor = json["cursor"]
232
+ end
233
+
234
+ cursor
235
+ end
236
+
237
+ OBJECTS_TABLE = {
238
+ "account" => Inbox::Account,
239
+ "calendar" => Inbox::Calendar,
240
+ "draft" => Inbox::Draft,
241
+ "thread" => Inbox::Thread,
242
+ "contact" => Inbox::Contact,
243
+ "event" => Inbox::Event,
244
+ "file" => Inbox::File,
245
+ "message" => Inbox::Message,
246
+ "tag" => Inbox::Tag,
247
+ "folder" => Inbox::Folder,
248
+ "label" => Inbox::Label,
249
+ }
250
+
251
+ def _build_exclude_types(exclude_types)
252
+ exclude_string = "&exclude_types="
253
+
254
+ exclude_types.each do |value|
255
+ count = 0
256
+ if OBJECTS_TABLE.has_value?(value)
257
+ param_name = OBJECTS_TABLE.key(value)
258
+ exclude_string += "#{param_name},"
259
+ end
260
+ end
261
+
262
+ exclude_string = exclude_string[0..-2]
263
+ end
264
+
265
+ def deltas(cursor, exclude_types=[])
266
+ raise 'Please provide a block for receiving the delta objects' if !block_given?
267
+ exclude_string = ""
268
+
269
+ if exclude_types.any?
270
+ exclude_string = _build_exclude_types(exclude_types)
271
+ end
272
+
273
+ # loop and yield deltas until we've come to the end.
274
+ loop do
275
+ path = self.url_for_path("/delta?cursor=#{cursor}#{exclude_string}")
276
+ json = nil
277
+
278
+ RestClient.get(path) do |response,request,result|
279
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
280
+ end
281
+
282
+ start_cursor = json["cursor_start"]
283
+ end_cursor = json["cursor_end"]
284
+
285
+ json["deltas"].each do |delta|
286
+ if not OBJECTS_TABLE.has_key?(delta['object'])
287
+ next
288
+ end
289
+
290
+ cls = OBJECTS_TABLE[delta['object']]
291
+ obj = cls.new(self)
292
+
293
+ case delta["event"]
294
+ when 'create', 'modify'
295
+ obj.inflate(delta['attributes'])
296
+ obj.cursor = delta["cursor"]
297
+ yield delta["event"], obj
298
+ when 'delete'
299
+ obj.id = delta["id"]
300
+ obj.cursor = delta["cursor"]
301
+ yield delta["event"], obj
302
+ end
303
+ end
304
+
305
+ break if start_cursor == end_cursor
306
+ cursor = end_cursor
307
+ end
308
+ end
309
+
310
+ def delta_stream(cursor, exclude_types=[], timeout=0)
311
+ raise 'Please provide a block for receiving the delta objects' if !block_given?
312
+
313
+ exclude_string = ""
314
+
315
+ if exclude_types.any?
316
+ exclude_string = _build_exclude_types(exclude_types)
317
+ end
318
+
319
+ # loop and yield deltas indefinitely.
320
+ path = self.url_for_path("/delta/streaming?cursor=#{cursor}#{exclude_string}")
321
+
322
+ parser = Yajl::Parser.new(:symbolize_keys => false)
323
+ parser.on_parse_complete = proc do |data|
324
+ delta = Inbox.interpret_response(OpenStruct.new(:code => '200'), data, {:expected_class => Object, :result_parsed => true})
325
+
326
+ if not OBJECTS_TABLE.has_key?(delta['object'])
327
+ next
328
+ end
329
+
330
+ cls = OBJECTS_TABLE[delta['object']]
331
+ obj = cls.new(self)
332
+
333
+ case delta["event"]
334
+ when 'create', 'modify'
335
+ obj.inflate(delta['attributes'])
336
+ obj.cursor = delta["cursor"]
337
+ yield delta["event"], obj
338
+ when 'delete'
339
+ obj.id = delta["id"]
340
+ obj.cursor = delta["cursor"]
341
+ yield delta["event"], obj
342
+ end
343
+ end
344
+
345
+ EventMachine.run do
346
+ http = EventMachine::HttpRequest.new(path, :connect_timeout => 0, :inactivity_timeout => timeout).get(:keepalive => true)
347
+ http.stream do |chunk|
348
+ parser << chunk
349
+ end
350
+ http.errback do
351
+ raise UnexpectedResponse.new http.error
352
+ end
353
+ end
137
354
  end
138
355
  end
139
356
  end
@@ -68,12 +68,12 @@ module Inbox
68
68
  end
69
69
 
70
70
  def files
71
- @files ||= RestfulModelCollection.new(File, @_api, @namespace_id, {:message_id=>@id})
71
+ @files ||= RestfulModelCollection.new(File, @_api, {:message_id=>@id})
72
72
  end
73
73
 
74
74
  def raw
75
75
  model = nil
76
- collection = RestfulModelCollection.new(Message, @_api, @namespace_id, {:message_id=>@id})
76
+ collection = RestfulModelCollection.new(Message, @_api, {:message_id=>@id})
77
77
  RestClient.get("#{collection.url}/#{id}/", :accept => 'message/rfc822'){ |response,request,result|
78
78
  response
79
79
  }
@@ -1,9 +1,26 @@
1
- require 'version'
2
- require 'rest-client'
3
- require 'restful_model_collection'
4
1
  require 'json'
5
- require 'namespace'
2
+ require 'rest-client'
3
+ require 'yajl'
4
+ require 'em-http'
5
+ require 'ostruct'
6
+
7
+ require 'account'
8
+ require 'api_account'
9
+ require 'api_thread'
10
+ require 'calendar'
6
11
  require 'account'
12
+ require 'tag'
13
+ require 'message'
14
+ require 'draft'
15
+ require 'contact'
16
+ require 'file'
17
+ require 'calendar'
18
+ require 'event'
19
+ require 'folder'
20
+ require 'restful_model'
21
+ require 'restful_model_collection'
22
+ require 'version'
23
+
7
24
 
8
25
  module Inbox
9
26
 
@@ -122,18 +139,218 @@ module Inbox
122
139
  end
123
140
  end
124
141
 
125
- # Convenience Methods
142
+ # API Methods
143
+ def threads
144
+ @threads ||= RestfulModelCollection.new(Thread, self)
145
+ end
126
146
 
127
- def namespaces
128
- @namespaces ||= RestfulModelCollection.new(Namespace, self, nil)
129
- @namespaces
147
+ def tags
148
+ @tags ||= RestfulModelCollection.new(Tag, self)
130
149
  end
131
150
 
132
- # Billing Methods
151
+ def messages
152
+ @messages ||= RestfulModelCollection.new(Message, self)
153
+ end
154
+
155
+ def files
156
+ @files ||= RestfulModelCollection.new(File, self)
157
+ end
158
+
159
+ def drafts
160
+ @drafts ||= RestfulModelCollection.new(Draft, self)
161
+ end
162
+
163
+ def contacts
164
+ @contacts ||= RestfulModelCollection.new(Contact, self)
165
+ end
166
+
167
+ def calendars
168
+ @calendars ||= RestfulModelCollection.new(Calendar, self)
169
+ end
170
+
171
+ def events
172
+ @events ||= RestfulModelCollection.new(Event, self)
173
+ end
174
+
175
+ def folders
176
+ @folders ||= RestfulModelCollection.new(Folder, self)
177
+ end
178
+
179
+ def labels
180
+ @labels ||= RestfulModelCollection.new(Label, self)
181
+ end
182
+
183
+ def account
184
+ path = self.url_for_path("/account")
185
+
186
+ RestClient.get(path, {}) do |response,request,result|
187
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
188
+ model = APIAccount.new(self)
189
+ model.inflate(json)
190
+ model
191
+ end
192
+ end
193
+
194
+ def using_hosted_api?
195
+ return !@app_id.nil?
196
+ end
133
197
 
134
198
  def accounts
135
- @accounts ||= ManagementModelCollection.new(Account, self, nil)
136
- @accounts
199
+ if self.using_hosted_api?
200
+ @accounts ||= ManagementModelCollection.new(Account, self)
201
+ else
202
+ @accounts ||= RestfulModelCollection.new(APIAccount, self)
203
+ end
204
+ end
205
+
206
+ def get_cursor(timestamp)
207
+ # Get the cursor corresponding to a specific timestamp.
208
+ warn "Nylas#get_cursor is deprecated. Use Nylas#latest_cursor instead."
209
+
210
+ path = self.url_for_path("/delta/generate_cursor")
211
+ data = { :start => timestamp }
212
+
213
+ cursor = nil
214
+
215
+ RestClient.post(path, data.to_json, :content_type => :json) do |response,request,result|
216
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
217
+ cursor = json["cursor"]
218
+ end
219
+
220
+ cursor
221
+ end
222
+
223
+ def latest_cursor
224
+ # Get the cursor corresponding to a specific timestamp.
225
+ path = self.url_for_path("/delta/latest_cursor")
226
+
227
+ cursor = nil
228
+
229
+ RestClient.post(path, :content_type => :json) do |response,request,result|
230
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
231
+ cursor = json["cursor"]
232
+ end
233
+
234
+ cursor
235
+ end
236
+
237
+ OBJECTS_TABLE = {
238
+ "account" => Inbox::Account,
239
+ "calendar" => Inbox::Calendar,
240
+ "draft" => Inbox::Draft,
241
+ "thread" => Inbox::Thread,
242
+ "contact" => Inbox::Contact,
243
+ "event" => Inbox::Event,
244
+ "file" => Inbox::File,
245
+ "message" => Inbox::Message,
246
+ "tag" => Inbox::Tag,
247
+ "folder" => Inbox::Folder,
248
+ "label" => Inbox::Label,
249
+ }
250
+
251
+ def _build_exclude_types(exclude_types)
252
+ exclude_string = "&exclude_types="
253
+
254
+ exclude_types.each do |value|
255
+ count = 0
256
+ if OBJECTS_TABLE.has_value?(value)
257
+ param_name = OBJECTS_TABLE.key(value)
258
+ exclude_string += "#{param_name},"
259
+ end
260
+ end
261
+
262
+ exclude_string = exclude_string[0..-2]
263
+ end
264
+
265
+ def deltas(cursor, exclude_types=[])
266
+ raise 'Please provide a block for receiving the delta objects' if !block_given?
267
+ exclude_string = ""
268
+
269
+ if exclude_types.any?
270
+ exclude_string = _build_exclude_types(exclude_types)
271
+ end
272
+
273
+ # loop and yield deltas until we've come to the end.
274
+ loop do
275
+ path = self.url_for_path("/delta?cursor=#{cursor}#{exclude_string}")
276
+ json = nil
277
+
278
+ RestClient.get(path) do |response,request,result|
279
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
280
+ end
281
+
282
+ start_cursor = json["cursor_start"]
283
+ end_cursor = json["cursor_end"]
284
+
285
+ json["deltas"].each do |delta|
286
+ if not OBJECTS_TABLE.has_key?(delta['object'])
287
+ next
288
+ end
289
+
290
+ cls = OBJECTS_TABLE[delta['object']]
291
+ obj = cls.new(self)
292
+
293
+ case delta["event"]
294
+ when 'create', 'modify'
295
+ obj.inflate(delta['attributes'])
296
+ obj.cursor = delta["cursor"]
297
+ yield delta["event"], obj
298
+ when 'delete'
299
+ obj.id = delta["id"]
300
+ obj.cursor = delta["cursor"]
301
+ yield delta["event"], obj
302
+ end
303
+ end
304
+
305
+ break if start_cursor == end_cursor
306
+ cursor = end_cursor
307
+ end
308
+ end
309
+
310
+ def delta_stream(cursor, exclude_types=[], timeout=0)
311
+ raise 'Please provide a block for receiving the delta objects' if !block_given?
312
+
313
+ exclude_string = ""
314
+
315
+ if exclude_types.any?
316
+ exclude_string = _build_exclude_types(exclude_types)
317
+ end
318
+
319
+ # loop and yield deltas indefinitely.
320
+ path = self.url_for_path("/delta/streaming?cursor=#{cursor}#{exclude_string}")
321
+
322
+ parser = Yajl::Parser.new(:symbolize_keys => false)
323
+ parser.on_parse_complete = proc do |data|
324
+ delta = Inbox.interpret_response(OpenStruct.new(:code => '200'), data, {:expected_class => Object, :result_parsed => true})
325
+
326
+ if not OBJECTS_TABLE.has_key?(delta['object'])
327
+ next
328
+ end
329
+
330
+ cls = OBJECTS_TABLE[delta['object']]
331
+ obj = cls.new(self)
332
+
333
+ case delta["event"]
334
+ when 'create', 'modify'
335
+ obj.inflate(delta['attributes'])
336
+ obj.cursor = delta["cursor"]
337
+ yield delta["event"], obj
338
+ when 'delete'
339
+ obj.id = delta["id"]
340
+ obj.cursor = delta["cursor"]
341
+ yield delta["event"], obj
342
+ end
343
+ end
344
+
345
+ EventMachine.run do
346
+ http = EventMachine::HttpRequest.new(path, :connect_timeout => 0, :inactivity_timeout => timeout).get(:keepalive => true)
347
+ http.stream do |chunk|
348
+ parser << chunk
349
+ end
350
+ http.errback do
351
+ raise UnexpectedResponse.new http.error
352
+ end
353
+ end
137
354
  end
138
355
  end
139
356
  end
@@ -7,7 +7,7 @@ module Inbox
7
7
  include Inbox::Parameters
8
8
 
9
9
  parameter :id
10
- parameter :namespace_id
10
+ parameter :account_id
11
11
  parameter :cursor # Only used by the delta sync API
12
12
  time_attr_accessor :created_at
13
13
 
@@ -15,9 +15,9 @@ module Inbox
15
15
  "#{self.to_s.downcase}s".split('::').last
16
16
  end
17
17
 
18
- def initialize(api, namespace_id = nil)
18
+ def initialize(api, account_id = nil)
19
19
  raise StandardError.new unless api.class <= Inbox::API
20
- @namespace_id = namespace_id
20
+ @account_id = account_id
21
21
  @_api = api
22
22
  end
23
23
 
@@ -41,7 +41,7 @@ module Inbox
41
41
 
42
42
  def url(action = "")
43
43
  action = "/#{action}" unless action.empty?
44
- @_api.url_for_path("/n/#{@namespace_id}/#{self.class.collection_name}/#{id}#{action}")
44
+ @_api.url_for_path("/#{self.class.collection_name}/#{id}#{action}")
45
45
  end
46
46
 
47
47
  def as_json(options = {})
@@ -5,11 +5,10 @@ module Inbox
5
5
 
6
6
  attr_accessor :filters
7
7
 
8
- def initialize(model_class, api, namespace_id, filters = {})
8
+ def initialize(model_class, api, filters = {})
9
9
  raise StandardError.new unless api.class <= Inbox::API
10
10
  @model_class = model_class
11
11
  @filters = filters
12
- @namespace_id = namespace_id
13
12
  @_api = api
14
13
  end
15
14
 
@@ -93,7 +92,7 @@ module Inbox
93
92
  for key in args.keys
94
93
  args[key.to_s] = args[key]
95
94
  end
96
- model = @model_class.new(@_api, @namespace_id)
95
+ model = @model_class.new(@_api)
97
96
  model.inflate(args)
98
97
  model
99
98
  end
@@ -115,8 +114,7 @@ module Inbox
115
114
  end
116
115
 
117
116
  def url
118
- prefix = "/n/#{@namespace_id}" if @namespace_id
119
- @_api.url_for_path("#{prefix}/#{@model_class.collection_name}")
117
+ @_api.url_for_path("/#{@model_class.collection_name}")
120
118
  end
121
119
 
122
120
  private
@@ -1,3 +1,3 @@
1
1
  module Inbox
2
- VERSION = "0.18.2"
2
+ VERSION = "1.0.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Gotow
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-08-05 00:00:00.000000000 Z
13
+ date: 2015-08-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client
@@ -203,6 +203,7 @@ extra_rdoc_files:
203
203
  - README.md
204
204
  files:
205
205
  - lib/account.rb
206
+ - lib/api_account.rb
206
207
  - lib/api_thread.rb
207
208
  - lib/calendar.rb
208
209
  - lib/contact.rb
@@ -213,7 +214,6 @@ files:
213
214
  - lib/inbox.rb
214
215
  - lib/label.rb
215
216
  - lib/message.rb
216
- - lib/namespace.rb
217
217
  - lib/nylas.rb
218
218
  - lib/parameters.rb
219
219
  - lib/restful_model.rb
@@ -1,210 +0,0 @@
1
- require 'restful_model'
2
- require 'account'
3
- require 'tag'
4
- require 'message'
5
- require 'draft'
6
- require 'contact'
7
- require 'file'
8
- require 'calendar'
9
- require 'event'
10
- require 'folder'
11
- require 'yajl'
12
- require 'em-http'
13
- require 'ostruct'
14
-
15
- # Rather than saying require 'thread', we need to explicitly force
16
- # the thread model to load. Otherwise, we can't reference it below.
17
- # Thread still refers to the built-in Thread type, and Inbox::Thread
18
- # is undefined.
19
- load "api_thread.rb"
20
-
21
- module Inbox
22
-
23
- class Namespace < RestfulModel
24
-
25
- parameter :account_id
26
- parameter :name
27
- parameter :email_address
28
- parameter :provider
29
-
30
- def self.collection_name
31
- "n"
32
- end
33
-
34
- def threads
35
- @threads ||= RestfulModelCollection.new(Thread, @_api, @id)
36
- end
37
-
38
- def tags
39
- @tags ||= RestfulModelCollection.new(Tag, @_api, @id)
40
- end
41
-
42
- def messages
43
- @messages ||= RestfulModelCollection.new(Message, @_api, @id)
44
- end
45
-
46
- def files
47
- @files ||= RestfulModelCollection.new(File, @_api, @id)
48
- end
49
-
50
- def drafts
51
- @drafts ||= RestfulModelCollection.new(Draft, @_api, @id)
52
- end
53
-
54
- def contacts
55
- @contacts ||= RestfulModelCollection.new(Contact, @_api, @id)
56
- end
57
-
58
- def calendars
59
- @calendars ||= RestfulModelCollection.new(Calendar, @_api, @id)
60
- end
61
-
62
- def events
63
- @events ||= RestfulModelCollection.new(Event, @_api, @id)
64
- end
65
-
66
- def folders
67
- @folders ||= RestfulModelCollection.new(Folder, @_api, @id)
68
- end
69
-
70
- def labels
71
- @labels ||= RestfulModelCollection.new(Label, @_api, @id)
72
- end
73
-
74
- def get_cursor(timestamp)
75
- # Get the cursor corresponding to a specific timestamp.
76
- path = @_api.url_for_path("/n/#{@namespace_id}/delta/generate_cursor")
77
- data = { :start => timestamp }
78
-
79
- cursor = nil
80
-
81
- RestClient.post(path, data.to_json, :content_type => :json) do |response,request,result|
82
- json = Inbox.interpret_response(result, response, {:expected_class => Object})
83
- cursor = json["cursor"]
84
- end
85
-
86
- cursor
87
- end
88
-
89
- OBJECTS_TABLE = {
90
- "account" => Inbox::Account,
91
- "calendar" => Inbox::Calendar,
92
- "draft" => Inbox::Draft,
93
- "thread" => Inbox::Thread,
94
- "contact" => Inbox::Contact,
95
- "event" => Inbox::Event,
96
- "file" => Inbox::File,
97
- "message" => Inbox::Message,
98
- "namespace" => Inbox::Namespace,
99
- "tag" => Inbox::Tag,
100
- "folder" => Inbox::Folder,
101
- "label" => Inbox::Label,
102
- }
103
-
104
- def _build_exclude_types(exclude_types)
105
- exclude_string = "&exclude_types="
106
-
107
- exclude_types.each do |value|
108
- count = 0
109
- if OBJECTS_TABLE.has_value?(value)
110
- param_name = OBJECTS_TABLE.key(value)
111
- exclude_string += "#{param_name},"
112
- end
113
- end
114
-
115
- exclude_string = exclude_string[0..-2]
116
- end
117
-
118
- def deltas(cursor, exclude_types=[])
119
- raise 'Please provide a block for receiving the delta objects' if !block_given?
120
- exclude_string = ""
121
-
122
- if exclude_types.any?
123
- exclude_string = _build_exclude_types(exclude_types)
124
- end
125
-
126
- # loop and yield deltas until we've come to the end.
127
- loop do
128
- path = @_api.url_for_path("/n/#{@namespace_id}/delta?cursor=#{cursor}#{exclude_string}")
129
- json = nil
130
-
131
- RestClient.get(path) do |response,request,result|
132
- json = Inbox.interpret_response(result, response, {:expected_class => Object})
133
- end
134
-
135
- start_cursor = json["cursor_start"]
136
- end_cursor = json["cursor_end"]
137
-
138
- json["deltas"].each do |delta|
139
- if not OBJECTS_TABLE.has_key?(delta['object'])
140
- next
141
- end
142
-
143
- cls = OBJECTS_TABLE[delta['object']]
144
- obj = cls.new(@_api, @namespace_id)
145
-
146
- case delta["event"]
147
- when 'create', 'modify'
148
- obj.inflate(delta['attributes'])
149
- obj.cursor = delta["cursor"]
150
- yield delta["event"], obj
151
- when 'delete'
152
- obj.id = delta["id"]
153
- obj.cursor = delta["cursor"]
154
- yield delta["event"], obj
155
- end
156
- end
157
-
158
- break if start_cursor == end_cursor
159
- cursor = end_cursor
160
- end
161
- end
162
-
163
- def delta_stream(cursor, exclude_types=[], timeout=0)
164
- raise 'Please provide a block for receiving the delta objects' if !block_given?
165
-
166
- exclude_string = ""
167
-
168
- if exclude_types.any?
169
- exclude_string = _build_exclude_types(exclude_types)
170
- end
171
-
172
- # loop and yield deltas indefinitely.
173
- path = @_api.url_for_path("/n/#{@namespace_id}/delta/streaming?cursor=#{cursor}#{exclude_string}")
174
-
175
- parser = Yajl::Parser.new(:symbolize_keys => false)
176
- parser.on_parse_complete = proc do |data|
177
- delta = Inbox.interpret_response(OpenStruct.new(:code => '200'), data, {:expected_class => Object, :result_parsed => true})
178
-
179
- if not OBJECTS_TABLE.has_key?(delta['object'])
180
- next
181
- end
182
-
183
- cls = OBJECTS_TABLE[delta['object']]
184
- obj = cls.new(@_api, @namespace_id)
185
-
186
- case delta["event"]
187
- when 'create', 'modify'
188
- obj.inflate(delta['attributes'])
189
- obj.cursor = delta["cursor"]
190
- yield delta["event"], obj
191
- when 'delete'
192
- obj.id = delta["id"]
193
- obj.cursor = delta["cursor"]
194
- yield delta["event"], obj
195
- end
196
- end
197
-
198
- EventMachine.run do
199
- http = EventMachine::HttpRequest.new(path, :connect_timeout => 0, :inactivity_timeout => timeout).get(:keepalive => true)
200
- http.stream do |chunk|
201
- parser << chunk
202
- end
203
- http.errback do
204
- raise UnexpectedResponse.new http.error
205
- end
206
- end
207
- end
208
-
209
- end
210
- end