nylas 5.17.0 → 6.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nylas/client.rb +121 -0
  3. data/lib/nylas/config.rb +19 -0
  4. data/lib/nylas/errors.rb +63 -89
  5. data/lib/nylas/handler/api_operations.rb +162 -0
  6. data/lib/nylas/handler/http_client.rb +252 -0
  7. data/lib/nylas/resources/applications.rb +27 -0
  8. data/lib/nylas/resources/attachments.rb +65 -0
  9. data/lib/nylas/resources/auth.rb +209 -0
  10. data/lib/nylas/resources/calendars.rb +101 -0
  11. data/lib/nylas/resources/connectors.rb +80 -0
  12. data/lib/nylas/resources/contacts.rb +89 -0
  13. data/lib/nylas/resources/credentials.rb +75 -0
  14. data/lib/nylas/resources/drafts.rb +121 -0
  15. data/lib/nylas/resources/events.rb +98 -0
  16. data/lib/nylas/resources/folders.rb +73 -0
  17. data/lib/nylas/resources/grants.rb +59 -0
  18. data/lib/nylas/resources/messages.rb +135 -0
  19. data/lib/nylas/resources/redirect_uris.rb +68 -0
  20. data/lib/nylas/resources/resource.rb +18 -0
  21. data/lib/nylas/resources/smart_compose.rb +36 -0
  22. data/lib/nylas/resources/threads.rb +62 -0
  23. data/lib/nylas/resources/webhooks.rb +121 -0
  24. data/lib/nylas/utils/file_utils.rb +61 -0
  25. data/lib/nylas/version.rb +1 -1
  26. data/lib/nylas.rb +31 -148
  27. metadata +88 -247
  28. data/lib/nylas/account.rb +0 -56
  29. data/lib/nylas/api.rb +0 -246
  30. data/lib/nylas/application_details.rb +0 -13
  31. data/lib/nylas/calendar.rb +0 -46
  32. data/lib/nylas/calendar_collection.rb +0 -144
  33. data/lib/nylas/categorize.rb +0 -14
  34. data/lib/nylas/collection.rb +0 -175
  35. data/lib/nylas/component.rb +0 -35
  36. data/lib/nylas/component_collection.rb +0 -10
  37. data/lib/nylas/constraints.rb +0 -56
  38. data/lib/nylas/contact.rb +0 -53
  39. data/lib/nylas/contact_group.rb +0 -23
  40. data/lib/nylas/current_account.rb +0 -23
  41. data/lib/nylas/delta.rb +0 -56
  42. data/lib/nylas/deltas.rb +0 -19
  43. data/lib/nylas/deltas_collection.rb +0 -40
  44. data/lib/nylas/draft.rb +0 -100
  45. data/lib/nylas/email_address.rb +0 -12
  46. data/lib/nylas/event.rb +0 -144
  47. data/lib/nylas/event_collection.rb +0 -15
  48. data/lib/nylas/event_conferencing.rb +0 -12
  49. data/lib/nylas/event_conferencing_autocreate.rb +0 -10
  50. data/lib/nylas/event_conferencing_details.rb +0 -14
  51. data/lib/nylas/event_notification.rb +0 -17
  52. data/lib/nylas/file.rb +0 -75
  53. data/lib/nylas/filter_attributes.rb +0 -25
  54. data/lib/nylas/folder.rb +0 -26
  55. data/lib/nylas/free_busy.rb +0 -13
  56. data/lib/nylas/free_busy_collection.rb +0 -48
  57. data/lib/nylas/http_client.rb +0 -279
  58. data/lib/nylas/im_address.rb +0 -11
  59. data/lib/nylas/job_status.rb +0 -27
  60. data/lib/nylas/job_status_collection.rb +0 -21
  61. data/lib/nylas/label.rb +0 -27
  62. data/lib/nylas/logging.rb +0 -41
  63. data/lib/nylas/message.rb +0 -98
  64. data/lib/nylas/message_headers.rb +0 -27
  65. data/lib/nylas/message_tracking.rb +0 -13
  66. data/lib/nylas/model/attributable.rb +0 -89
  67. data/lib/nylas/model/attribute_definition.rb +0 -24
  68. data/lib/nylas/model/attributes.rb +0 -97
  69. data/lib/nylas/model/list_attribute_definition.rb +0 -39
  70. data/lib/nylas/model/transferable.rb +0 -53
  71. data/lib/nylas/model.rb +0 -217
  72. data/lib/nylas/native_authentication.rb +0 -39
  73. data/lib/nylas/neural.rb +0 -87
  74. data/lib/nylas/neural_categorizer.rb +0 -29
  75. data/lib/nylas/neural_clean_conversation.rb +0 -33
  76. data/lib/nylas/neural_contact_link.rb +0 -11
  77. data/lib/nylas/neural_contact_name.rb +0 -11
  78. data/lib/nylas/neural_message_options.rb +0 -35
  79. data/lib/nylas/neural_ocr.rb +0 -16
  80. data/lib/nylas/neural_sentiment_analysis.rb +0 -17
  81. data/lib/nylas/neural_signature_contact.rb +0 -81
  82. data/lib/nylas/neural_signature_extraction.rb +0 -18
  83. data/lib/nylas/new_message.rb +0 -39
  84. data/lib/nylas/nylas_date.rb +0 -25
  85. data/lib/nylas/open_hours.rb +0 -15
  86. data/lib/nylas/outbox.rb +0 -116
  87. data/lib/nylas/outbox_job_status.rb +0 -19
  88. data/lib/nylas/outbox_message.rb +0 -17
  89. data/lib/nylas/participant.rb +0 -13
  90. data/lib/nylas/phone_number.rb +0 -11
  91. data/lib/nylas/physical_address.rb +0 -17
  92. data/lib/nylas/raw_message.rb +0 -25
  93. data/lib/nylas/recurrence.rb +0 -11
  94. data/lib/nylas/registry.rb +0 -42
  95. data/lib/nylas/room_resource.rb +0 -19
  96. data/lib/nylas/rsvp.rb +0 -24
  97. data/lib/nylas/scheduler.rb +0 -51
  98. data/lib/nylas/scheduler_booking_confirmation.rb +0 -24
  99. data/lib/nylas/scheduler_booking_request.rb +0 -17
  100. data/lib/nylas/scheduler_collection.rb +0 -104
  101. data/lib/nylas/scheduler_config.rb +0 -20
  102. data/lib/nylas/scheduler_time_slot.rb +0 -14
  103. data/lib/nylas/search_collection.rb +0 -10
  104. data/lib/nylas/send_grid_verified_status.rb +0 -12
  105. data/lib/nylas/services/tunnel.rb +0 -128
  106. data/lib/nylas/thread.rb +0 -66
  107. data/lib/nylas/time_slot.rb +0 -16
  108. data/lib/nylas/time_slot_capacity.rb +0 -13
  109. data/lib/nylas/timespan.rb +0 -20
  110. data/lib/nylas/token_info.rb +0 -20
  111. data/lib/nylas/types.rb +0 -168
  112. data/lib/nylas/web_page.rb +0 -11
  113. data/lib/nylas/webhook.rb +0 -111
  114. 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