nylas 5.17.0 → 6.0.3
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 +4 -4
- data/lib/nylas/client.rb +121 -0
- data/lib/nylas/config.rb +19 -0
- data/lib/nylas/errors.rb +63 -89
- data/lib/nylas/handler/api_operations.rb +162 -0
- data/lib/nylas/handler/http_client.rb +252 -0
- data/lib/nylas/resources/applications.rb +27 -0
- data/lib/nylas/resources/attachments.rb +65 -0
- data/lib/nylas/resources/auth.rb +209 -0
- data/lib/nylas/resources/calendars.rb +101 -0
- data/lib/nylas/resources/connectors.rb +80 -0
- data/lib/nylas/resources/contacts.rb +89 -0
- data/lib/nylas/resources/credentials.rb +75 -0
- data/lib/nylas/resources/drafts.rb +121 -0
- data/lib/nylas/resources/events.rb +98 -0
- data/lib/nylas/resources/folders.rb +73 -0
- data/lib/nylas/resources/grants.rb +59 -0
- data/lib/nylas/resources/messages.rb +135 -0
- data/lib/nylas/resources/redirect_uris.rb +68 -0
- data/lib/nylas/resources/resource.rb +18 -0
- data/lib/nylas/resources/smart_compose.rb +36 -0
- data/lib/nylas/resources/threads.rb +62 -0
- data/lib/nylas/resources/webhooks.rb +121 -0
- data/lib/nylas/utils/file_utils.rb +61 -0
- data/lib/nylas/version.rb +1 -1
- data/lib/nylas.rb +31 -148
- metadata +88 -247
- data/lib/nylas/account.rb +0 -56
- data/lib/nylas/api.rb +0 -246
- data/lib/nylas/application_details.rb +0 -13
- data/lib/nylas/calendar.rb +0 -46
- data/lib/nylas/calendar_collection.rb +0 -144
- data/lib/nylas/categorize.rb +0 -14
- data/lib/nylas/collection.rb +0 -175
- data/lib/nylas/component.rb +0 -35
- data/lib/nylas/component_collection.rb +0 -10
- data/lib/nylas/constraints.rb +0 -56
- data/lib/nylas/contact.rb +0 -53
- data/lib/nylas/contact_group.rb +0 -23
- data/lib/nylas/current_account.rb +0 -23
- data/lib/nylas/delta.rb +0 -56
- data/lib/nylas/deltas.rb +0 -19
- data/lib/nylas/deltas_collection.rb +0 -40
- data/lib/nylas/draft.rb +0 -100
- data/lib/nylas/email_address.rb +0 -12
- data/lib/nylas/event.rb +0 -144
- data/lib/nylas/event_collection.rb +0 -15
- data/lib/nylas/event_conferencing.rb +0 -12
- data/lib/nylas/event_conferencing_autocreate.rb +0 -10
- data/lib/nylas/event_conferencing_details.rb +0 -14
- data/lib/nylas/event_notification.rb +0 -17
- data/lib/nylas/file.rb +0 -75
- data/lib/nylas/filter_attributes.rb +0 -25
- data/lib/nylas/folder.rb +0 -26
- data/lib/nylas/free_busy.rb +0 -13
- data/lib/nylas/free_busy_collection.rb +0 -48
- data/lib/nylas/http_client.rb +0 -279
- data/lib/nylas/im_address.rb +0 -11
- data/lib/nylas/job_status.rb +0 -27
- data/lib/nylas/job_status_collection.rb +0 -21
- data/lib/nylas/label.rb +0 -27
- data/lib/nylas/logging.rb +0 -41
- data/lib/nylas/message.rb +0 -98
- data/lib/nylas/message_headers.rb +0 -27
- data/lib/nylas/message_tracking.rb +0 -13
- data/lib/nylas/model/attributable.rb +0 -89
- data/lib/nylas/model/attribute_definition.rb +0 -24
- data/lib/nylas/model/attributes.rb +0 -97
- data/lib/nylas/model/list_attribute_definition.rb +0 -39
- data/lib/nylas/model/transferable.rb +0 -53
- data/lib/nylas/model.rb +0 -217
- data/lib/nylas/native_authentication.rb +0 -39
- data/lib/nylas/neural.rb +0 -87
- data/lib/nylas/neural_categorizer.rb +0 -29
- data/lib/nylas/neural_clean_conversation.rb +0 -33
- data/lib/nylas/neural_contact_link.rb +0 -11
- data/lib/nylas/neural_contact_name.rb +0 -11
- data/lib/nylas/neural_message_options.rb +0 -35
- data/lib/nylas/neural_ocr.rb +0 -16
- data/lib/nylas/neural_sentiment_analysis.rb +0 -17
- data/lib/nylas/neural_signature_contact.rb +0 -81
- data/lib/nylas/neural_signature_extraction.rb +0 -18
- data/lib/nylas/new_message.rb +0 -39
- data/lib/nylas/nylas_date.rb +0 -25
- data/lib/nylas/open_hours.rb +0 -15
- data/lib/nylas/outbox.rb +0 -116
- data/lib/nylas/outbox_job_status.rb +0 -19
- data/lib/nylas/outbox_message.rb +0 -17
- data/lib/nylas/participant.rb +0 -13
- data/lib/nylas/phone_number.rb +0 -11
- data/lib/nylas/physical_address.rb +0 -17
- data/lib/nylas/raw_message.rb +0 -25
- data/lib/nylas/recurrence.rb +0 -11
- data/lib/nylas/registry.rb +0 -42
- data/lib/nylas/room_resource.rb +0 -19
- data/lib/nylas/rsvp.rb +0 -24
- data/lib/nylas/scheduler.rb +0 -51
- data/lib/nylas/scheduler_booking_confirmation.rb +0 -24
- data/lib/nylas/scheduler_booking_request.rb +0 -17
- data/lib/nylas/scheduler_collection.rb +0 -104
- data/lib/nylas/scheduler_config.rb +0 -20
- data/lib/nylas/scheduler_time_slot.rb +0 -14
- data/lib/nylas/search_collection.rb +0 -10
- data/lib/nylas/send_grid_verified_status.rb +0 -12
- data/lib/nylas/services/tunnel.rb +0 -128
- data/lib/nylas/thread.rb +0 -66
- data/lib/nylas/time_slot.rb +0 -16
- data/lib/nylas/time_slot_capacity.rb +0 -13
- data/lib/nylas/timespan.rb +0 -20
- data/lib/nylas/token_info.rb +0 -20
- data/lib/nylas/types.rb +0 -168
- data/lib/nylas/web_page.rb +0 -11
- data/lib/nylas/webhook.rb +0 -111
- data/lib/nylas/when.rb +0 -75
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rest-client"
|
|
4
|
+
|
|
5
|
+
require_relative "../errors"
|
|
6
|
+
require_relative "../version"
|
|
7
|
+
|
|
8
|
+
# Module for working with HTTP Client
|
|
9
|
+
module Nylas
|
|
10
|
+
require "yajl"
|
|
11
|
+
require "base64"
|
|
12
|
+
|
|
13
|
+
# Plain HTTP client that can be used to interact with the Nylas API without any type casting.
|
|
14
|
+
module HttpClient
|
|
15
|
+
protected
|
|
16
|
+
|
|
17
|
+
attr_accessor :api_server
|
|
18
|
+
attr_writer :default_headers
|
|
19
|
+
|
|
20
|
+
# Sends a request to the Nylas API. Returns a successful response if the request succeeds, or a
|
|
21
|
+
# failed response if the request encounters a JSON parse error.
|
|
22
|
+
#
|
|
23
|
+
# @param method [Symbol] HTTP method for the API call. Either :get, :post, :delete, or :patch.
|
|
24
|
+
# @param path [String, nil] Relative path from the API Base. This is the preferred way to execute
|
|
25
|
+
# arbitrary or-not-yet-SDK-ified API commands.
|
|
26
|
+
# @param timeout [Integer, nil] Timeout value to send with the request.
|
|
27
|
+
# @param headers [Hash, {}] Additional HTTP headers to include in the payload.
|
|
28
|
+
# @param query [Hash, {}] Hash of names and values to include in the query section of the URI
|
|
29
|
+
# fragment.
|
|
30
|
+
# @param payload [Hash, nil] Body to send with the request.
|
|
31
|
+
# @param api_key [Hash, nil] API key to send with the request.
|
|
32
|
+
# @return [Object] Parsed JSON response from the API.
|
|
33
|
+
def execute(method:, path:, timeout:, headers: {}, query: {}, payload: nil, api_key: nil)
|
|
34
|
+
request = build_request(method: method, path: path, headers: headers,
|
|
35
|
+
query: query, payload: payload, api_key: api_key, timeout: timeout)
|
|
36
|
+
begin
|
|
37
|
+
rest_client_execute(**request) do |response, _request, result|
|
|
38
|
+
content_type = nil
|
|
39
|
+
if response.headers && response.headers[:content_type]
|
|
40
|
+
content_type = response.headers[:content_type].downcase
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
parse_json_evaluate_error(result.code.to_i, response, path, content_type)
|
|
44
|
+
end
|
|
45
|
+
rescue RestClient::Exceptions::OpenTimeout, RestClient::Exceptions::ReadTimeout
|
|
46
|
+
raise Nylas::NylasSdkTimeoutError.new(request[:path], timeout)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Sends a request to the Nylas API, specifically for downloading data.
|
|
51
|
+
# This method supports streaming the response by passing a block, which will be executed
|
|
52
|
+
# with each chunk of the response body as it is read. If no block is provided, the entire
|
|
53
|
+
# response body is returned.
|
|
54
|
+
#
|
|
55
|
+
# @param path [String] Relative path from the API Base. This is the preferred way to execute
|
|
56
|
+
# arbitrary or-not-yet-SDK-ified API commands.
|
|
57
|
+
# @param timeout [Integer] Timeout value to send with the request.
|
|
58
|
+
# @param headers [Hash, {}] Additional HTTP headers to include in the payload.
|
|
59
|
+
# @param query [Hash, {}] Hash of names and values to include in the query section of the URI
|
|
60
|
+
# fragment.
|
|
61
|
+
# @param api_key [Hash, nil] API key to send with the request.
|
|
62
|
+
# @yieldparam chunk [String] A chunk of the response body.
|
|
63
|
+
# @return [nil, String] Returns nil when a block is given (streaming mode).
|
|
64
|
+
# When no block is provided, the return is the entire raw response body.
|
|
65
|
+
def download_request(path:, timeout:, headers: {}, query: {}, api_key: nil, &block)
|
|
66
|
+
request, uri, http = setup_http(path, timeout, headers, query, api_key)
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
http.start do |setup_http|
|
|
70
|
+
get_request = Net::HTTP::Get.new(uri)
|
|
71
|
+
request[:headers].each { |key, value| get_request[key] = value }
|
|
72
|
+
|
|
73
|
+
handle_response(setup_http, get_request, path, &block)
|
|
74
|
+
end
|
|
75
|
+
rescue Net::OpenTimeout, Net::ReadTimeout
|
|
76
|
+
raise Nylas::NylasSdkTimeoutError.new(request[:url], timeout)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Builds a request sent to the Nylas API.
|
|
81
|
+
#
|
|
82
|
+
# @param method [Symbol] HTTP method for the API call. Either :get, :post, :delete, or :patch.
|
|
83
|
+
# @param path [String, nil] Relative path from the API Base.
|
|
84
|
+
# @param headers [Hash, {}] Additional HTTP headers to include in the payload.
|
|
85
|
+
# @param query [Hash, {}] Hash of names and values to include in the query section of the URI
|
|
86
|
+
# fragment.
|
|
87
|
+
# @param payload [Hash, nil] Body to send with the request.
|
|
88
|
+
# @param timeout [Integer, nil] Timeout value to send with the request.
|
|
89
|
+
# @param api_key [Hash, nil] API key to send with the request.
|
|
90
|
+
# @return [Object] The request information after processing. This includes an updated payload
|
|
91
|
+
# and headers.
|
|
92
|
+
def build_request(
|
|
93
|
+
method:, path: nil, headers: {}, query: {}, payload: nil, timeout: nil, api_key: nil
|
|
94
|
+
)
|
|
95
|
+
url = build_url(path, query)
|
|
96
|
+
resulting_headers = default_headers.merge(headers).merge(auth_header(api_key))
|
|
97
|
+
if !payload.nil? && !payload["multipart"]
|
|
98
|
+
payload = payload&.to_json
|
|
99
|
+
resulting_headers["Content-type"] = "application/json"
|
|
100
|
+
elsif !payload.nil? && payload["multipart"]
|
|
101
|
+
payload.delete("multipart")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
{ method: method, url: url, payload: payload, headers: resulting_headers, timeout: timeout }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Sets the default headers for API requests.
|
|
108
|
+
def default_headers
|
|
109
|
+
@default_headers ||= {
|
|
110
|
+
"X-Nylas-API-Wrapper" => "ruby",
|
|
111
|
+
"User-Agent" => "Nylas Ruby SDK #{Nylas::VERSION} - #{RUBY_VERSION}"
|
|
112
|
+
}
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Parses the response from the Nylas API.
|
|
116
|
+
def parse_response(response)
|
|
117
|
+
return response if response.is_a?(Enumerable)
|
|
118
|
+
|
|
119
|
+
Yajl::Parser.new(symbolize_names: true).parse(response)
|
|
120
|
+
rescue Yajl::ParseError
|
|
121
|
+
raise Nylas::JsonParseError
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
private
|
|
125
|
+
|
|
126
|
+
# Sends a request to the Nylas REST API.
|
|
127
|
+
#
|
|
128
|
+
# @param method [Symbol] HTTP method for the API call. Either :get, :post, :delete, or :patch.
|
|
129
|
+
# @param url [String] URL for the API call.
|
|
130
|
+
# @param headers [Hash] HTTP headers to include in the payload.
|
|
131
|
+
# @param payload [String, Hash] Body to send with the request.
|
|
132
|
+
# @param timeout [Hash] Timeout value to send with the request.
|
|
133
|
+
def rest_client_execute(method:, url:, headers:, payload:, timeout:, &block)
|
|
134
|
+
::RestClient::Request.execute(method: method, url: url, payload: payload,
|
|
135
|
+
headers: headers, timeout: timeout, &block)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def setup_http(path, timeout, headers, query, api_key)
|
|
139
|
+
request = build_request(method: :get, path: path, headers: headers,
|
|
140
|
+
query: query, api_key: api_key, timeout: timeout)
|
|
141
|
+
uri = URI(request[:url])
|
|
142
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
143
|
+
http.use_ssl = true
|
|
144
|
+
http.read_timeout = timeout
|
|
145
|
+
http.open_timeout = timeout
|
|
146
|
+
[request, uri, http]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def handle_response(http, get_request, path, &block)
|
|
150
|
+
http.request(get_request) do |response|
|
|
151
|
+
if response.is_a?(Net::HTTPSuccess)
|
|
152
|
+
return response.body unless block_given?
|
|
153
|
+
|
|
154
|
+
response.read_body(&block)
|
|
155
|
+
else
|
|
156
|
+
parse_json_evaluate_error(response.code.to_i, response.body, path, response["Content-Type"])
|
|
157
|
+
break
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Parses the response from the Nylas API and evaluates for errors.
|
|
163
|
+
def parse_json_evaluate_error(http_code, response, path, content_type = nil)
|
|
164
|
+
begin
|
|
165
|
+
response = parse_response(response) if content_type == "application/json"
|
|
166
|
+
rescue Nylas::JsonParseError
|
|
167
|
+
handle_failed_response(http_code, response, path)
|
|
168
|
+
raise
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
handle_failed_response(http_code, response, path)
|
|
172
|
+
response
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Handles failed responses from the Nylas API.
|
|
176
|
+
def handle_failed_response(http_code, response, path)
|
|
177
|
+
return if HTTP_SUCCESS_CODES.include?(http_code)
|
|
178
|
+
|
|
179
|
+
case response
|
|
180
|
+
when Hash
|
|
181
|
+
raise error_hash_to_exception(response, http_code, path)
|
|
182
|
+
else
|
|
183
|
+
raise NylasApiError.parse_error_response(response, http_code)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Converts error hashes to exceptions.
|
|
188
|
+
def error_hash_to_exception(response, status_code, path)
|
|
189
|
+
return if !response || !response.key?(:error)
|
|
190
|
+
|
|
191
|
+
if %W[#{api_uri}/v3/connect/token #{api_uri}/v3/connect/revoke].include?(path)
|
|
192
|
+
NylasOAuthError.new(response[:error], response[:error_description], response[:error_uri],
|
|
193
|
+
response[:error_code], status_code)
|
|
194
|
+
else
|
|
195
|
+
throw_error(response, status_code)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def throw_error(response, status_code)
|
|
200
|
+
error_obj = response[:error]
|
|
201
|
+
provider_error = error_obj.fetch(:provider_error, nil)
|
|
202
|
+
|
|
203
|
+
NylasApiError.new(error_obj[:type], error_obj[:message], status_code, provider_error,
|
|
204
|
+
response[:request_id])
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Adds query parameters to a URL.
|
|
208
|
+
# @param url [String] The base URL.
|
|
209
|
+
# @param query [Hash] The query parameters to add to the URL.
|
|
210
|
+
# @return [String] Processed URL, including query params.
|
|
211
|
+
def build_url(url, query = nil)
|
|
212
|
+
unless query.nil? || query.empty?
|
|
213
|
+
uri = URI.parse(url)
|
|
214
|
+
uri = build_query(uri, query)
|
|
215
|
+
url = uri.to_s
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
url
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Build the query string for a URI.
|
|
222
|
+
# @param uri [URI] URL to add the query to.
|
|
223
|
+
# @param query [Hash] The query params to include in the query.
|
|
224
|
+
# @return [URI] The URI object with the query parameters included.
|
|
225
|
+
def build_query(uri, query)
|
|
226
|
+
query.each do |key, value|
|
|
227
|
+
case value
|
|
228
|
+
when Array
|
|
229
|
+
value.each do |item|
|
|
230
|
+
qs = "#{URI.encode_www_form_component(key)}=#{URI.encode_www_form_component(item)}"
|
|
231
|
+
uri.query = [uri.query, qs].compact.join("&")
|
|
232
|
+
end
|
|
233
|
+
when Hash
|
|
234
|
+
value.each do |k, v|
|
|
235
|
+
qs = "#{URI.encode_www_form_component(key)}=#{URI.encode_www_form_component("#{k}:#{v}")}"
|
|
236
|
+
uri.query = [uri.query, qs].compact.join("&")
|
|
237
|
+
end
|
|
238
|
+
else
|
|
239
|
+
qs = "#{URI.encode_www_form_component(key)}=#{URI.encode_www_form_component(value)}"
|
|
240
|
+
uri.query = [uri.query, qs].compact.join("&")
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
uri
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Set the authorization header for an API query.
|
|
248
|
+
def auth_header(api_key)
|
|
249
|
+
{ "Authorization" => "Bearer #{api_key}" }
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "resource"
|
|
4
|
+
require_relative "redirect_uris"
|
|
5
|
+
require_relative "../handler/api_operations"
|
|
6
|
+
|
|
7
|
+
module Nylas
|
|
8
|
+
# Application
|
|
9
|
+
class Applications < Resource
|
|
10
|
+
include ApiOperations::Get
|
|
11
|
+
|
|
12
|
+
attr_reader :redirect_uris
|
|
13
|
+
|
|
14
|
+
# Initializes the application.
|
|
15
|
+
def initialize(sdk_instance)
|
|
16
|
+
super(sdk_instance)
|
|
17
|
+
@redirect_uris = RedirectUris.new(sdk_instance)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Get application details.
|
|
21
|
+
#
|
|
22
|
+
# @return [Array(Hash, String)] Application details and API Request ID.
|
|
23
|
+
def get_details
|
|
24
|
+
get(path: "#{api_uri}/v3/applications")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "resource"
|
|
4
|
+
require_relative "../handler/api_operations"
|
|
5
|
+
|
|
6
|
+
module Nylas
|
|
7
|
+
# Nylas Attachment API
|
|
8
|
+
class Attachments < Resource
|
|
9
|
+
include ApiOperations::Get
|
|
10
|
+
|
|
11
|
+
# Return metadata of an attachment.
|
|
12
|
+
#
|
|
13
|
+
# @param identifier [String] Grant ID or email account to query.
|
|
14
|
+
# @param attachment_id [String] The id of the attachment to retrieve.
|
|
15
|
+
# @param query_params [Hash] The query parameters to include in the request.
|
|
16
|
+
# @return [Array(Hash, String)] The attachment and API request ID.
|
|
17
|
+
def find(identifier:, attachment_id:, query_params:)
|
|
18
|
+
get(
|
|
19
|
+
path: "#{api_uri}/v3/grants/#{identifier}/attachments/#{attachment_id}",
|
|
20
|
+
query_params: query_params
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Download the attachment data.
|
|
25
|
+
#
|
|
26
|
+
# This method supports streaming the download by passing a block, which will
|
|
27
|
+
# be called with each chunk of the response body as it is read. If no block
|
|
28
|
+
# is given, the entire response will be read into memory and returned (not recommended
|
|
29
|
+
# for large files).
|
|
30
|
+
#
|
|
31
|
+
# @param identifier [String] Grant ID or email account to query.
|
|
32
|
+
# @param attachment_id [String] The ID of the attachment to be downloaded.
|
|
33
|
+
# @param query_params [Hash] The query parameters to include in the request.
|
|
34
|
+
# @yieldparam chunk [String] A chunk of the response body.
|
|
35
|
+
# @return [nil, String] Returns nil when a block is given (streaming mode).
|
|
36
|
+
# When no block is provided, the return is the entire raw response body.
|
|
37
|
+
def download(identifier:, attachment_id:, query_params:, &block)
|
|
38
|
+
download_request(
|
|
39
|
+
path: "#{api_uri}/v3/grants/#{identifier}/attachments/#{attachment_id}/download",
|
|
40
|
+
query: query_params,
|
|
41
|
+
api_key: api_key,
|
|
42
|
+
timeout: timeout,
|
|
43
|
+
&block
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Download the attachment as a byte array.
|
|
48
|
+
#
|
|
49
|
+
# @param identifier [String] Grant ID or email account to query.
|
|
50
|
+
# @param attachment_id [String] The ID of the attachment to be downloaded.
|
|
51
|
+
# @param query_params [Hash] The query parameters to include in the request.
|
|
52
|
+
# @return [nil, Array(Integer)] Returns nil when a block is given (streaming mode).
|
|
53
|
+
# When no block is provided, the return is the entire raw response body.
|
|
54
|
+
def download_bytes(identifier:, attachment_id:, query_params:)
|
|
55
|
+
data = download_request(
|
|
56
|
+
path: "#{api_uri}/v3/grants/#{identifier}/attachments/#{attachment_id}/download",
|
|
57
|
+
query: query_params,
|
|
58
|
+
api_key: api_key,
|
|
59
|
+
timeout: timeout
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
data&.bytes
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "base64"
|
|
5
|
+
require "securerandom"
|
|
6
|
+
require "ostruct"
|
|
7
|
+
require "uri"
|
|
8
|
+
|
|
9
|
+
require_relative "resource"
|
|
10
|
+
require_relative "grants"
|
|
11
|
+
require_relative "../handler/api_operations"
|
|
12
|
+
|
|
13
|
+
module Nylas
|
|
14
|
+
# Auth
|
|
15
|
+
class Auth < Resource
|
|
16
|
+
include ApiOperations::Post
|
|
17
|
+
include ApiOperations::Get
|
|
18
|
+
|
|
19
|
+
# Builds the URL for authenticating users to your application with OAuth 2.0.
|
|
20
|
+
#
|
|
21
|
+
# @param config [Hash] Configuration for building the URL.
|
|
22
|
+
# @return [String] URL for hosted authentication.
|
|
23
|
+
def url_for_oauth2(config)
|
|
24
|
+
url_auth_builder(config).to_s
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Exchanges an authorization code for an access token.
|
|
28
|
+
#
|
|
29
|
+
# @param request [Hash] Code exchange request.
|
|
30
|
+
# @return [Hash] Token object.
|
|
31
|
+
def exchange_code_for_token(request)
|
|
32
|
+
request[:grant_type] = "authorization_code"
|
|
33
|
+
|
|
34
|
+
execute_token_request(request)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Create a Grant via Custom Authentication.
|
|
38
|
+
#
|
|
39
|
+
# @param request_body [Hash] The values to create the Grant with.
|
|
40
|
+
# @return [Array(Hash, String)] Created grant and API Request ID.
|
|
41
|
+
def custom_authentication(request_body)
|
|
42
|
+
post(
|
|
43
|
+
path: "#{api_uri}/v3/connect/custom",
|
|
44
|
+
request_body: request_body
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Refreshes an access token.
|
|
49
|
+
#
|
|
50
|
+
# @param request [Hash] Code exchange request.
|
|
51
|
+
# @return [Hash] Refreshed token object.
|
|
52
|
+
def refresh_access_token(request)
|
|
53
|
+
request[:grant_type] = "refresh_token"
|
|
54
|
+
|
|
55
|
+
execute_token_request(request)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Builds the URL for authenticating users to your application with OAuth 2.0 and PKCE.
|
|
59
|
+
# IMPORTANT: You must store the 'secret' returned to use it inside the CodeExchange flow.
|
|
60
|
+
#
|
|
61
|
+
# @param config [Hash] Configuration for building the URL.
|
|
62
|
+
# @return [Hash] URL for hosted authentication with the secret and the hashed secret.
|
|
63
|
+
def url_for_oauth2_pkce(config)
|
|
64
|
+
url = url_auth_builder(config)
|
|
65
|
+
|
|
66
|
+
# Generates a secret and hashes it.
|
|
67
|
+
secret = SecureRandom.uuid
|
|
68
|
+
secret_hash = hash_pkce_secret(secret)
|
|
69
|
+
|
|
70
|
+
# Adds code challenge to URL generation.
|
|
71
|
+
url.query = build_query_with_pkce(config, secret_hash)
|
|
72
|
+
|
|
73
|
+
# Returns the URL with secret and hashed secret.
|
|
74
|
+
{ secret: secret, secret_hash: secret_hash, url: url.to_s }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Builds the URL for admin consent authentication for Microsoft.
|
|
78
|
+
#
|
|
79
|
+
# @param config [Hash] Configuration for the authentication request.
|
|
80
|
+
# @return [String] URL for hosted authentication.
|
|
81
|
+
def url_for_admin_consent(config)
|
|
82
|
+
config_with_provider = config.merge("provider" => "microsoft")
|
|
83
|
+
url = url_auth_builder(config_with_provider)
|
|
84
|
+
url.query = build_query_with_admin_consent(config)
|
|
85
|
+
|
|
86
|
+
url.to_s
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Revokes a single access token.
|
|
90
|
+
#
|
|
91
|
+
# @param token [String] Access token to revoke.
|
|
92
|
+
# @return [Boolean] True if the access token was revoked successfully.
|
|
93
|
+
def revoke(token)
|
|
94
|
+
post(
|
|
95
|
+
path: "#{api_uri}/v3/connect/revoke",
|
|
96
|
+
query_params: {
|
|
97
|
+
token: token
|
|
98
|
+
}
|
|
99
|
+
)
|
|
100
|
+
true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Detects the provider of an email address.
|
|
104
|
+
# @param params [Hash] Parameters to detect the provider.
|
|
105
|
+
# @return [Array(Hash, String)] Detected provider, if found and API Request ID.
|
|
106
|
+
def detect_provider(params)
|
|
107
|
+
post(
|
|
108
|
+
path: "#{api_uri}/v3/providers/detect",
|
|
109
|
+
query_params: params
|
|
110
|
+
)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
private
|
|
114
|
+
|
|
115
|
+
# Builds the query with admin consent authentication for Microsoft.
|
|
116
|
+
#
|
|
117
|
+
# @param config [Hash] Configuration for the query.
|
|
118
|
+
# @return [String] Updated list of parameters, including those specific to admin
|
|
119
|
+
# consent.
|
|
120
|
+
def build_query_with_admin_consent(config)
|
|
121
|
+
params = build_http_query(config)
|
|
122
|
+
|
|
123
|
+
# Appends new params specific for admin consent.
|
|
124
|
+
params[:provider] = "microsoft"
|
|
125
|
+
params[:response_type] = "adminconsent"
|
|
126
|
+
params[:credential_id] = config[:credential_id] if config[:credential_id]
|
|
127
|
+
|
|
128
|
+
URI.encode_www_form(params).gsub("+", "%20")
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Builds the query with PKCE.
|
|
132
|
+
#
|
|
133
|
+
# @param config [Hash] Configuration for the query.
|
|
134
|
+
# @param secret_hash [Hash] Hashed secret.
|
|
135
|
+
# @return [String] Updated list of encoded parameters, including those specific
|
|
136
|
+
# to PKCE.
|
|
137
|
+
def build_query_with_pkce(config, secret_hash)
|
|
138
|
+
params = build_http_query(config)
|
|
139
|
+
|
|
140
|
+
# Appends new PKCE specific params.
|
|
141
|
+
params[:code_challenge_method] = "s256"
|
|
142
|
+
params[:code_challenge] = secret_hash
|
|
143
|
+
|
|
144
|
+
URI.encode_www_form(params).gsub("+", "%20")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Builds the authentication URL.
|
|
148
|
+
#
|
|
149
|
+
# @param config [Hash] Configuration for the query.
|
|
150
|
+
# @return [URI] List of components for the authentication URL.
|
|
151
|
+
def url_auth_builder(config)
|
|
152
|
+
builder = URI.parse(api_uri)
|
|
153
|
+
builder.path = "/v3/connect/auth"
|
|
154
|
+
builder.query = URI.encode_www_form(build_http_query(config)).gsub(/\+/, "%20")
|
|
155
|
+
|
|
156
|
+
builder
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Builds the query.
|
|
160
|
+
#
|
|
161
|
+
# @param config [Hash] Configuration for the query.
|
|
162
|
+
# @return [Hash] List of parameters to encode in the query.
|
|
163
|
+
def build_http_query(config)
|
|
164
|
+
params = {
|
|
165
|
+
client_id: config[:client_id],
|
|
166
|
+
redirect_uri: config[:redirect_uri],
|
|
167
|
+
access_type: config[:access_type] || "online",
|
|
168
|
+
response_type: "code"
|
|
169
|
+
}
|
|
170
|
+
params[:provider] = config[:provider] if config[:provider]
|
|
171
|
+
params[:prompt] = config[:prompt] if config[:prompt]
|
|
172
|
+
params[:metadata] = config[:metadata] if config[:metadata]
|
|
173
|
+
params[:state] = config[:state] if config[:state]
|
|
174
|
+
params[:scope] = config[:scope].join(" ") if config[:scope]
|
|
175
|
+
if config[:login_hint]
|
|
176
|
+
params[:login_hint] = config[:login_hint]
|
|
177
|
+
params[:include_grant_scopes] = config[:include_grant_scopes].to_s if config[:include_grant_scopes]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
params
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Hash a plain text secret for use in PKCE.
|
|
184
|
+
#
|
|
185
|
+
# @param secret [String] The plain text secret to hash.
|
|
186
|
+
# @return [String] The hashed secret with base64 encoding (without padding).
|
|
187
|
+
def hash_pkce_secret(secret)
|
|
188
|
+
sha256_hash = Digest::SHA256.hexdigest(secret)
|
|
189
|
+
Base64.urlsafe_encode64(sha256_hash, padding: false)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Sends the token request to the Nylas API.
|
|
193
|
+
#
|
|
194
|
+
# @param request [Hash] Code exchange request.
|
|
195
|
+
def execute_token_request(request)
|
|
196
|
+
request[:client_secret] = api_key if request[:client_secret].nil?
|
|
197
|
+
|
|
198
|
+
execute(
|
|
199
|
+
method: :post,
|
|
200
|
+
path: "#{api_uri}/v3/connect/token",
|
|
201
|
+
query: {},
|
|
202
|
+
payload: request,
|
|
203
|
+
headers: {},
|
|
204
|
+
api_key: api_key,
|
|
205
|
+
timeout: timeout
|
|
206
|
+
)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "resource"
|
|
4
|
+
require_relative "../handler/api_operations"
|
|
5
|
+
|
|
6
|
+
module Nylas
|
|
7
|
+
# Nylas Calendar API
|
|
8
|
+
class Calendars < Resource
|
|
9
|
+
include ApiOperations::Get
|
|
10
|
+
include ApiOperations::Post
|
|
11
|
+
include ApiOperations::Put
|
|
12
|
+
include ApiOperations::Delete
|
|
13
|
+
|
|
14
|
+
# Return all calendars.
|
|
15
|
+
#
|
|
16
|
+
# @param identifier [String] Grant ID or email account to query.
|
|
17
|
+
# @param query_params [Hash, nil] Query params to pass to the request.
|
|
18
|
+
# @return [Array(Array(Hash), String, String)] The list of calendars, API Request ID, and next cursor.
|
|
19
|
+
def list(identifier:, query_params: nil)
|
|
20
|
+
get_list(
|
|
21
|
+
path: "#{api_uri}/v3/grants/#{identifier}/calendars",
|
|
22
|
+
query_params: query_params
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Return a calendar.
|
|
27
|
+
#
|
|
28
|
+
# @param identifier [String] Grant ID or email account to query.
|
|
29
|
+
# @param calendar_id [String] The id of the calendar to return.
|
|
30
|
+
# Use "primary" to refer to the primary calendar associated with grant.
|
|
31
|
+
# @return [Array(Hash, String)] The calendar and API request ID.
|
|
32
|
+
def find(identifier:, calendar_id:)
|
|
33
|
+
get(
|
|
34
|
+
path: "#{api_uri}/v3/grants/#{identifier}/calendars/#{calendar_id}"
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Create a calendar.
|
|
39
|
+
#
|
|
40
|
+
# @param identifier [String] Grant ID or email account in which to create the object.
|
|
41
|
+
# @param request_body [Hash] The values to create the calendar with.
|
|
42
|
+
# @return [Array(Hash, String)] The created calendar and API Request ID.
|
|
43
|
+
def create(identifier:, request_body:)
|
|
44
|
+
post(
|
|
45
|
+
path: "#{api_uri}/v3/grants/#{identifier}/calendars",
|
|
46
|
+
request_body: request_body
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Update a calendar.
|
|
51
|
+
#
|
|
52
|
+
# @param identifier [String] Grant ID or email account in which to update an object.
|
|
53
|
+
# @param calendar_id [String] The id of the calendar to update.
|
|
54
|
+
# Use "primary" to refer to the primary calendar associated with grant.
|
|
55
|
+
# @param request_body [Hash] The values to update the calendar with
|
|
56
|
+
# @return [Array(Hash, String)] The updated calendar and API Request ID.
|
|
57
|
+
def update(identifier:, calendar_id:, request_body:)
|
|
58
|
+
put(
|
|
59
|
+
path: "#{api_uri}/v3/grants/#{identifier}/calendars/#{calendar_id}",
|
|
60
|
+
request_body: request_body
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Delete a calendar.
|
|
65
|
+
#
|
|
66
|
+
# @param identifier [String] Grant ID or email account from which to delete an object.
|
|
67
|
+
# @param calendar_id [String] The id of the calendar to delete.
|
|
68
|
+
# Use "primary" to refer to the primary calendar associated with grant.
|
|
69
|
+
# @return [Array(TrueClass, String)] True and the API Request ID for the delete operation.
|
|
70
|
+
def destroy(identifier:, calendar_id:)
|
|
71
|
+
_, request_id = delete(
|
|
72
|
+
path: "#{api_uri}/v3/grants/#{identifier}/calendars/#{calendar_id}"
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
[true, request_id]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Checks multiple calendars to find available time slots for a single meeting.
|
|
79
|
+
#
|
|
80
|
+
# @param request_body [Hash] Request body to pass to the request.
|
|
81
|
+
# @return [Array(Hash, String)] Availability object and API request ID.
|
|
82
|
+
def get_availability(request_body:)
|
|
83
|
+
post(
|
|
84
|
+
path: "#{api_uri}/v3/calendars/availability",
|
|
85
|
+
request_body: request_body
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Get the free/busy schedule for a list of email addresses.
|
|
90
|
+
#
|
|
91
|
+
# @param identifier [str] The identifier of the grant to act upon.
|
|
92
|
+
# @param request_body [Hash] Request body to pass to the request.
|
|
93
|
+
# @return [Array(Array(Hash), String)] The free/busy response.
|
|
94
|
+
def get_free_busy(identifier:, request_body:)
|
|
95
|
+
post(
|
|
96
|
+
path: "#{api_uri}/v3/grants/#{identifier}/calendars/free-busy",
|
|
97
|
+
request_body: request_body
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|