nylas 0.15.5

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/lib/calendar.rb ADDED
@@ -0,0 +1,15 @@
1
+ require 'restful_model'
2
+ require 'event'
3
+
4
+ module Inbox
5
+ class Calendar < RestfulModel
6
+
7
+ parameter :name
8
+ parameter :description
9
+
10
+ def events
11
+ @events ||= RestfulModelCollection.new(Event, @_api, @namespace, {:calendar_id=>@id})
12
+ end
13
+
14
+ end
15
+ end
data/lib/contact.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'restful_model'
2
+
3
+ module Inbox
4
+ class Contact < RestfulModel
5
+
6
+ parameter :name
7
+ parameter :email
8
+
9
+ end
10
+ end
data/lib/draft.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'restful_model'
2
+
3
+ module Inbox
4
+ class Draft < Message
5
+
6
+ parameter :thread_id
7
+ parameter :version
8
+ parameter :reply_to_message_id
9
+
10
+ def attach(file)
11
+ file.save! unless file.id
12
+ @file_ids.push(file.id)
13
+ end
14
+
15
+ def send!
16
+ url = @_api.url_for_path("/n/#{@namespace_id}/send")
17
+ if @id
18
+ data = {:draft_id => @id, :version => @version}
19
+ else
20
+ data = as_json()
21
+ end
22
+
23
+ ::RestClient.post(url, data.to_json, :content_type => :json) do |response, request, result|
24
+ json = Inbox.interpret_response(result, response, :expected_class => Object)
25
+ self.inflate(json)
26
+ end
27
+
28
+ self
29
+ end
30
+
31
+ end
32
+ end
data/lib/event.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'restful_model'
2
+
3
+ module Inbox
4
+ class Event < RestfulModel
5
+
6
+ parameter :title
7
+ parameter :description
8
+ parameter :location
9
+ parameter :read_only
10
+ parameter :participants
11
+ parameter :when
12
+ parameter :calendar_id
13
+ parameter :namespace_id
14
+ parameter :recurrence
15
+ parameter :cancelled
16
+ parameter :master_event_id
17
+ parameter :original_start_time
18
+
19
+ def as_json(options = {})
20
+ hash = super(options)
21
+
22
+ # Delete nil values from the hash
23
+ hash.delete_if { |key, value| value.nil? }
24
+
25
+ # The API doesn't like to receive: "object": "timespan" in the when block.
26
+ if hash.has_key?('when') and hash['when'].has_key?('object')
27
+ hash['when'].delete('object')
28
+ end
29
+
30
+ return hash
31
+ end
32
+
33
+ end
34
+ end
data/lib/file.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'restful_model'
2
+
3
+ module Inbox
4
+ class File < RestfulModel
5
+
6
+ parameter :size
7
+ parameter :filename
8
+ parameter :content_type
9
+ parameter :is_embedded
10
+ parameter :message_id
11
+
12
+ # For uploading the file
13
+ parameter :file
14
+
15
+ def inflate(json)
16
+ super
17
+ content_type = json["content-type"] if json["content-type"]
18
+ end
19
+
20
+ def save!
21
+ ::RestClient.post(url, {:file => @file}) do |response, request, result|
22
+ json = Inbox.interpret_response(result, response, :expected_class => Object)
23
+ json = json[0] if (json.class == Array)
24
+ inflate(json)
25
+ end
26
+ self
27
+ end
28
+
29
+ end
30
+ end
31
+
data/lib/inbox.rb ADDED
@@ -0,0 +1,141 @@
1
+ require 'version'
2
+ require 'rest-client'
3
+ require 'restful_model_collection'
4
+ require 'json'
5
+ require 'namespace'
6
+ require 'account'
7
+
8
+ module Inbox
9
+
10
+ class AccessDenied < StandardError; end
11
+ class ResourceNotFound < StandardError; end
12
+ class NoAuthToken < StandardError; end
13
+ class UnexpectedAccountAction < StandardError; end
14
+ class UnexpectedResponse < StandardError; end
15
+ class APIError < StandardError
16
+ attr_accessor :error_type
17
+ def initialize(type, error)
18
+ super(error)
19
+ self.error_type = type
20
+ end
21
+ end
22
+ class InvalidRequest < APIError; end
23
+ class MessageRejected < APIError; end
24
+ class SendingQuotaExceeded < APIError; end
25
+ class ServiceUnavailable < APIError; end
26
+
27
+ def self.interpret_http_status(result)
28
+ # Handle HTTP errors and RestClient errors
29
+ raise ResourceNotFound.new if result.code.to_i == 404
30
+ raise AccessDenied.new if result.code.to_i == 403
31
+ end
32
+
33
+ def self.interpret_response(result, result_content, options = {})
34
+ # Handle HTTP errors
35
+ Inbox.interpret_http_status(result)
36
+
37
+ # Handle content expectation errors
38
+ raise UnexpectedResponse.new if options[:expected_class] && result_content.empty?
39
+ json = JSON.parse(result_content)
40
+ if json.is_a?(Hash) && (json['type'] == 'api_error' or json['type'] == 'invalid_request_error')
41
+ if result.code.to_i == 400
42
+ exc = InvalidRequest
43
+ elsif result.code.to_i == 402
44
+ exc = MessageRejected
45
+ elsif result.code.to_i == 429
46
+ exc = SendingQuotaExceeded
47
+ elsif result.code.to_i == 503
48
+ exc = ServiceUnavailable
49
+ else
50
+ exc = APIError
51
+ end
52
+ raise exc.new(json['type'], json['message'])
53
+ end
54
+ raise UnexpectedResponse.new(result.msg) if result.is_a?(Net::HTTPClientError)
55
+ raise UnexpectedResponse.new if options[:expected_class] && !json.is_a?(options[:expected_class])
56
+ json
57
+
58
+ rescue JSON::ParserError => e
59
+ # Handle parsing errors
60
+ raise UnexpectedResponse.new(e.message)
61
+ end
62
+
63
+
64
+ class API
65
+ attr_accessor :api_server
66
+ attr_reader :access_token
67
+ attr_reader :app_id
68
+ attr_reader :app_secret
69
+
70
+ def initialize(app_id, app_secret, access_token = nil, api_server = 'https://api.nylas.com',
71
+ service_domain = 'api.nylas.com')
72
+ raise "When overriding the Inbox API server address, you must include https://" unless api_server.include?('://')
73
+ @api_server = api_server
74
+ @access_token = access_token
75
+ @app_secret = app_secret
76
+ @app_id = app_id
77
+ @service_domain = service_domain
78
+ @version = Inbox::VERSION
79
+
80
+ if ::RestClient.before_execution_procs.empty?
81
+ ::RestClient.add_before_execution_proc do |req, params|
82
+ req.add_field('X-Inbox-API-Wrapper', 'ruby')
83
+ req['User-Agent'] = "Ruby SDK #{@version} - #{RUBY_VERSION}"
84
+ end
85
+ end
86
+ end
87
+
88
+ def url_for_path(path)
89
+ raise NoAuthToken.new if @access_token == nil and (@app_secret != nil or @app_id != nil)
90
+ protocol, domain = @api_server.split('//')
91
+ "#{protocol}//#{@access_token}:@#{domain}#{path}"
92
+ end
93
+
94
+ def url_for_authentication(redirect_uri, login_hint = '', options = {})
95
+ trialString = 'false'
96
+ if options[:trial] == true
97
+ trialString = 'true'
98
+ end
99
+ "https://#{@service_domain}/oauth/authorize?client_id=#{@app_id}&trial=#{trialString}&response_type=code&scope=email&login_hint=#{login_hint}&redirect_uri=#{redirect_uri}"
100
+ end
101
+
102
+ def url_for_management
103
+ protocol, domain = @api_server.split('//')
104
+ accounts_path = "#{protocol}//#{@app_secret}:@#{domain}/a/#{@app_id}/accounts"
105
+ end
106
+
107
+ def set_access_token(token)
108
+ @access_token = token
109
+ end
110
+
111
+ def token_for_code(code)
112
+ data = {
113
+ 'client_id' => app_id,
114
+ 'client_secret' => app_secret,
115
+ 'grant_type' => 'authorization_code',
116
+ 'code' => code
117
+ }
118
+
119
+ ::RestClient.post("https://#{@service_domain}/oauth/token", data) do |response, request, result|
120
+ json = Inbox.interpret_response(result, response, :expected_class => Object)
121
+ return json['access_token']
122
+ end
123
+ end
124
+
125
+ # Convenience Methods
126
+
127
+ def namespaces
128
+ @namespaces ||= RestfulModelCollection.new(Namespace, self, nil)
129
+ @namespaces
130
+ end
131
+
132
+ # Billing Methods
133
+
134
+ def accounts
135
+ @accounts ||= ManagementModelCollection.new(Account, self, nil)
136
+ @accounts
137
+ end
138
+ end
139
+ end
140
+
141
+ Nylas = Inbox.clone
data/lib/message.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'restful_model'
2
+ require 'file'
3
+ require 'rfc2882'
4
+
5
+ module Inbox
6
+ class Message < RestfulModel
7
+
8
+ parameter :subject
9
+ parameter :snippet
10
+ parameter :from
11
+ parameter :to
12
+ parameter :cc
13
+ parameter :bcc
14
+ parameter :date
15
+ parameter :thread_id
16
+ parameter :body
17
+ parameter :unread
18
+
19
+ def inflate(json)
20
+ super
21
+ @to ||= []
22
+ @cc ||= []
23
+ @bcc ||= []
24
+ end
25
+
26
+ def files
27
+ @files ||= RestfulModelCollection.new(File, @_api, @namespace_id, {:message_id=>@id})
28
+ end
29
+
30
+ def raw
31
+ model = nil
32
+ collection = RestfulModelCollection.new(Message, @_api, @namespace_id, {:message_id=>@id})
33
+ RestClient.get("#{collection.url}/#{id}/rfc2822"){ |response,request,result|
34
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
35
+ model = Rfc2822.new(@_api)
36
+ model.inflate(json)
37
+ }
38
+ model
39
+ end
40
+ end
41
+ end
data/lib/namespace.rb ADDED
@@ -0,0 +1,147 @@
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
+
11
+ # Rather than saying require 'thread', we need to explicitly force
12
+ # the thread model to load. Otherwise, we can't reference it below.
13
+ # Thread still refers to the built-in Thread type, and Inbox::Thread
14
+ # is undefined.
15
+ load "api_thread.rb"
16
+
17
+ module Inbox
18
+
19
+ class Namespace < RestfulModel
20
+
21
+ parameter :account_id
22
+ parameter :name
23
+ parameter :email_address
24
+ parameter :provider
25
+
26
+ def self.collection_name
27
+ "n"
28
+ end
29
+
30
+ def threads
31
+ @threads ||= RestfulModelCollection.new(Thread, @_api, @id)
32
+ end
33
+
34
+ def tags
35
+ @tags ||= RestfulModelCollection.new(Tag, @_api, @id)
36
+ end
37
+
38
+ def messages
39
+ @messages ||= RestfulModelCollection.new(Message, @_api, @id)
40
+ end
41
+
42
+ def files
43
+ @files ||= RestfulModelCollection.new(File, @_api, @id)
44
+ end
45
+
46
+ def drafts
47
+ @drafts ||= RestfulModelCollection.new(Draft, @_api, @id)
48
+ end
49
+
50
+ def contacts
51
+ @contacts ||= RestfulModelCollection.new(Contact, @_api, @id)
52
+ end
53
+
54
+ def calendars
55
+ @calendars ||= RestfulModelCollection.new(Calendar, @_api, @id)
56
+ end
57
+
58
+ def events
59
+ @events ||= RestfulModelCollection.new(Event, @_api, @id)
60
+ end
61
+
62
+ def get_cursor(timestamp)
63
+ # Get the cursor corresponding to a specific timestamp.
64
+ path = @_api.url_for_path("/n/#{@namespace_id}/delta/generate_cursor")
65
+ data = { :start => timestamp }
66
+
67
+ cursor = nil
68
+
69
+ RestClient.post(path, data.to_json, :content_type => :json) do |response,request,result|
70
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
71
+ cursor = json["cursor"]
72
+ end
73
+
74
+ cursor
75
+ end
76
+
77
+ OBJECTS_TABLE = {
78
+ "account" => Inbox::Account,
79
+ "calendar" => Inbox::Calendar,
80
+ "draft" => Inbox::Draft,
81
+ "thread" => Inbox::Thread,
82
+ "contact" => Inbox::Contact,
83
+ "event" => Inbox::Event,
84
+ "file" => Inbox::File,
85
+ "message" => Inbox::Message,
86
+ "namespace" => Inbox::Namespace,
87
+ "tag" => Inbox::Tag,
88
+ }
89
+
90
+ def deltas(cursor, exclude_types=[])
91
+ raise 'Please provide a block for receiving the delta objects' if !block_given?
92
+ exclude_string = ""
93
+
94
+ if exclude_types.any?
95
+ exclude_string = "&exclude_types="
96
+
97
+ exclude_types.each do |value|
98
+ count = 0
99
+ if OBJECTS_TABLE.has_value?(value)
100
+ param_name = OBJECTS_TABLE.key(value)
101
+ exclude_string += "#{param_name},"
102
+ end
103
+ end
104
+ end
105
+
106
+ exclude_string = exclude_string[0..-2]
107
+
108
+ # loop and yield deltas until we've come to the end.
109
+ loop do
110
+ path = @_api.url_for_path("/n/#{@namespace_id}/delta?cursor=#{cursor}#{exclude_string}")
111
+ json = nil
112
+
113
+ RestClient.get(path) do |response,request,result|
114
+ json = Inbox.interpret_response(result, response, {:expected_class => Object})
115
+ end
116
+
117
+ start_cursor = json["cursor_start"]
118
+ end_cursor = json["cursor_end"]
119
+
120
+ json["deltas"].each do |delta|
121
+ object = delta['object']
122
+ if object == 'message'
123
+ # Drafts are messages underneath
124
+ object = delta['attributes']['object']
125
+ end
126
+ cls = OBJECTS_TABLE[object]
127
+ obj = cls.new(@_api, @namespace_id)
128
+
129
+ case delta["event"]
130
+ when 'create', 'modify'
131
+ obj.inflate(delta['attributes'])
132
+ obj.cursor = delta["cursor"]
133
+ yield delta["event"], obj
134
+ when 'delete'
135
+ obj.id = delta["id"]
136
+ obj.cursor = delta["cursor"]
137
+ yield delta["event"], obj
138
+ end
139
+ end
140
+
141
+ break if start_cursor == end_cursor
142
+ cursor = end_cursor
143
+ end
144
+ end
145
+
146
+ end
147
+ end