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.
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