nylas-legacy 5.17.0 → 5.18.0

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nylas-legacy/account.rb +56 -0
  3. data/lib/nylas-legacy/api.rb +265 -0
  4. data/lib/nylas-legacy/application_details.rb +13 -0
  5. data/lib/nylas-legacy/calendar.rb +46 -0
  6. data/lib/nylas-legacy/calendar_collection.rb +144 -0
  7. data/lib/nylas-legacy/categorize.rb +14 -0
  8. data/lib/nylas-legacy/collection.rb +175 -0
  9. data/lib/nylas-legacy/component.rb +35 -0
  10. data/lib/nylas-legacy/component_collection.rb +10 -0
  11. data/lib/nylas-legacy/constraints.rb +56 -0
  12. data/lib/nylas-legacy/contact.rb +53 -0
  13. data/lib/nylas-legacy/contact_group.rb +23 -0
  14. data/lib/nylas-legacy/current_account.rb +23 -0
  15. data/lib/nylas-legacy/delta.rb +56 -0
  16. data/lib/nylas-legacy/deltas.rb +19 -0
  17. data/lib/nylas-legacy/deltas_collection.rb +40 -0
  18. data/lib/nylas-legacy/draft.rb +101 -0
  19. data/lib/nylas-legacy/email_address.rb +12 -0
  20. data/lib/nylas-legacy/errors.rb +111 -0
  21. data/lib/nylas-legacy/event.rb +144 -0
  22. data/lib/nylas-legacy/event_collection.rb +15 -0
  23. data/lib/nylas-legacy/event_conferencing.rb +12 -0
  24. data/lib/nylas-legacy/event_conferencing_autocreate.rb +10 -0
  25. data/lib/nylas-legacy/event_conferencing_details.rb +14 -0
  26. data/lib/nylas-legacy/event_notification.rb +17 -0
  27. data/lib/nylas-legacy/file.rb +75 -0
  28. data/lib/nylas-legacy/filter_attributes.rb +25 -0
  29. data/lib/nylas-legacy/folder.rb +26 -0
  30. data/lib/nylas-legacy/free_busy.rb +13 -0
  31. data/lib/nylas-legacy/free_busy_collection.rb +48 -0
  32. data/lib/nylas-legacy/http_client.rb +280 -0
  33. data/lib/nylas-legacy/im_address.rb +11 -0
  34. data/lib/nylas-legacy/job_status.rb +27 -0
  35. data/lib/nylas-legacy/job_status_collection.rb +21 -0
  36. data/lib/nylas-legacy/label.rb +27 -0
  37. data/lib/nylas-legacy/logging.rb +41 -0
  38. data/lib/nylas-legacy/message.rb +98 -0
  39. data/lib/nylas-legacy/message_headers.rb +27 -0
  40. data/lib/nylas-legacy/message_tracking.rb +13 -0
  41. data/lib/nylas-legacy/model/attributable.rb +89 -0
  42. data/lib/nylas-legacy/model/attribute_definition.rb +24 -0
  43. data/lib/nylas-legacy/model/attributes.rb +97 -0
  44. data/lib/nylas-legacy/model/list_attribute_definition.rb +39 -0
  45. data/lib/nylas-legacy/model/transferable.rb +53 -0
  46. data/lib/nylas-legacy/model.rb +217 -0
  47. data/lib/nylas-legacy/native_authentication.rb +39 -0
  48. data/lib/nylas-legacy/neural.rb +87 -0
  49. data/lib/nylas-legacy/neural_categorizer.rb +29 -0
  50. data/lib/nylas-legacy/neural_clean_conversation.rb +33 -0
  51. data/lib/nylas-legacy/neural_contact_link.rb +11 -0
  52. data/lib/nylas-legacy/neural_contact_name.rb +11 -0
  53. data/lib/nylas-legacy/neural_message_options.rb +35 -0
  54. data/lib/nylas-legacy/neural_ocr.rb +16 -0
  55. data/lib/nylas-legacy/neural_sentiment_analysis.rb +17 -0
  56. data/lib/nylas-legacy/neural_signature_contact.rb +81 -0
  57. data/lib/nylas-legacy/neural_signature_extraction.rb +18 -0
  58. data/lib/nylas-legacy/new_message.rb +41 -0
  59. data/lib/nylas-legacy/nylas_date.rb +25 -0
  60. data/lib/nylas-legacy/open_hours.rb +15 -0
  61. data/lib/nylas-legacy/outbox.rb +116 -0
  62. data/lib/nylas-legacy/outbox_job_status.rb +19 -0
  63. data/lib/nylas-legacy/outbox_message.rb +17 -0
  64. data/lib/nylas-legacy/participant.rb +13 -0
  65. data/lib/nylas-legacy/phone_number.rb +11 -0
  66. data/lib/nylas-legacy/physical_address.rb +17 -0
  67. data/lib/nylas-legacy/raw_message.rb +25 -0
  68. data/lib/nylas-legacy/recurrence.rb +11 -0
  69. data/lib/nylas-legacy/registry.rb +42 -0
  70. data/lib/nylas-legacy/room_resource.rb +19 -0
  71. data/lib/nylas-legacy/rsvp.rb +24 -0
  72. data/lib/nylas-legacy/scheduler.rb +51 -0
  73. data/lib/nylas-legacy/scheduler_booking_confirmation.rb +24 -0
  74. data/lib/nylas-legacy/scheduler_booking_request.rb +17 -0
  75. data/lib/nylas-legacy/scheduler_collection.rb +104 -0
  76. data/lib/nylas-legacy/scheduler_config.rb +20 -0
  77. data/lib/nylas-legacy/scheduler_time_slot.rb +14 -0
  78. data/lib/nylas-legacy/search_collection.rb +14 -0
  79. data/lib/nylas-legacy/send_grid_verified_status.rb +12 -0
  80. data/lib/nylas-legacy/services/tunnel.rb +128 -0
  81. data/lib/nylas-legacy/thread.rb +66 -0
  82. data/lib/nylas-legacy/time_slot.rb +16 -0
  83. data/lib/nylas-legacy/time_slot_capacity.rb +13 -0
  84. data/lib/nylas-legacy/timespan.rb +20 -0
  85. data/lib/nylas-legacy/token_info.rb +20 -0
  86. data/lib/nylas-legacy/types.rb +169 -0
  87. data/lib/nylas-legacy/version.rb +5 -0
  88. data/lib/nylas-legacy/web_page.rb +11 -0
  89. data/lib/nylas-legacy/webhook.rb +111 -0
  90. data/lib/nylas-legacy/when.rb +75 -0
  91. data/lib/nylas-legacy.rb +164 -0
  92. metadata +175 -3
@@ -0,0 +1,280 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ require "yajl"
5
+ require "base64"
6
+
7
+ # Plain HTTP client that can be used to interact with the Nylas API sans any type casting.
8
+ class HttpClient
9
+ module AuthMethod
10
+ BEARER = 1
11
+ BASIC = 2
12
+ end
13
+
14
+ HTTP_SUCCESS_CODES = [200, 201, 202, 302].freeze
15
+
16
+ HTTP_CODE_TO_EXCEPTIONS = {
17
+ 400 => InvalidRequest,
18
+ 401 => UnauthorizedRequest,
19
+ 402 => MessageRejected,
20
+ 403 => AccessDenied,
21
+ 404 => ResourceNotFound,
22
+ 405 => MethodNotAllowed,
23
+ 410 => ResourceRemoved,
24
+ 418 => TeapotError,
25
+ 422 => MailProviderError,
26
+ 429 => SendingQuotaExceeded,
27
+ 500 => InternalError,
28
+ 501 => EndpointNotYetImplemented,
29
+ 502 => BadGateway,
30
+ 503 => ServiceUnavailable,
31
+ 504 => RequestTimedOut
32
+ }.freeze
33
+
34
+ ENDPOINT_TIMEOUTS = {
35
+ "/oauth/authorize" => 345,
36
+ "/messages/search" => 350,
37
+ "/threads/search" => 350,
38
+ "/delta" => 3650,
39
+ "/delta/longpoll" => 3650,
40
+ "/delta/streaming" => 3650
41
+ }.freeze
42
+
43
+ SUPPORTED_API_VERSION = "2.5"
44
+
45
+ include Logging
46
+ attr_accessor :api_server
47
+ attr_writer :default_headers
48
+ attr_reader :access_token
49
+ attr_reader :app_id
50
+ attr_reader :app_secret
51
+
52
+ # @param app_id [String] Your application id from the Nylas Dashboard
53
+ # @param app_secret [String] Your application secret from the Nylas Dashboard
54
+ # @param access_token [String] (Optional) Your users access token.
55
+ # @param api_server [String] (Optional) Which Nylas API Server to connect to. Only change this if
56
+ # you're using a self-hosted Nylas instance.
57
+ # @return [NylasLegacy::HttpClient]
58
+ def initialize(app_id:, app_secret:, access_token: nil, api_server: "https://api.nylas.com")
59
+ unless api_server.include?("://")
60
+ raise "When overriding the Nylas API server address, you must include https://"
61
+ end
62
+
63
+ @api_server = api_server
64
+ @access_token = access_token
65
+ @app_secret = app_secret
66
+ @app_id = app_id
67
+ end
68
+
69
+ # @return [NylasLegacy::HttpClient[]
70
+ def as(access_token)
71
+ HttpClient.new(app_id: app_id, access_token: access_token,
72
+ app_secret: app_secret, api_server: api_server)
73
+ end
74
+
75
+ # Sends a request to the Nylas API and rai
76
+ # @param method [Symbol] HTTP method for the API call. Either :get, :post, :delete, or :patch
77
+ # @param path [String] (Optional, defaults to nil) - Relative path from the API Base. Preferred way to
78
+ # execute arbitrary or-not-yet-SDK-ified API commands.
79
+ # @param headers [Hash] (Optional, defaults to {}) - Additional HTTP headers to include in the payload.
80
+ # @param query [Hash] (Optional, defaults to {}) - Hash of names and values to include in the query
81
+ # section of the URI fragment
82
+ # @param payload [String,Hash] (Optional, defaults to nil) - Body to send with the request.
83
+ # @param auth_method [AuthMethod] (Optional, defaults to BEARER) - The authentication method.
84
+ # @return [Array Hash Stringn]
85
+ # rubocop:disable Metrics/MethodLength
86
+ def execute(method:, path: nil, headers: {}, query: {}, payload: nil, auth_method: nil)
87
+ timeout = ENDPOINT_TIMEOUTS.fetch(path, 230)
88
+ request = build_request(
89
+ method: method,
90
+ path: path,
91
+ headers: headers,
92
+ query: query,
93
+ payload: payload,
94
+ timeout: timeout,
95
+ auth_method: auth_method || AuthMethod::BEARER
96
+ )
97
+ rest_client_execute(**request) do |response, _request, result|
98
+ content_type = nil
99
+
100
+ if response.headers && response.headers[:content_type]
101
+ content_type = response.headers[:content_type].downcase
102
+ end
103
+
104
+ begin
105
+ response = parse_response(response) if content_type == "application/json"
106
+ rescue NylasLegacy::JsonParseError
107
+ handle_failed_response(result: result, response: response)
108
+ raise
109
+ end
110
+
111
+ handle_failed_response(result: result, response: response)
112
+ response
113
+ end
114
+ end
115
+ # rubocop:enable Metrics/MethodLength
116
+ inform_on :execute, level: :debug,
117
+ also_log: { result: true, values: %i[method url path headers query payload] }
118
+
119
+ def build_request(
120
+ method:,
121
+ path: nil,
122
+ headers: {},
123
+ query: {},
124
+ payload: nil,
125
+ timeout: nil,
126
+ auth_method: nil
127
+ )
128
+ url ||= url_for_path(path)
129
+ url = add_query_params_to_url(url, query)
130
+ resulting_headers = default_headers.merge(headers).merge(auth_header(auth_method))
131
+ { method: method, url: url, payload: payload, headers: resulting_headers, timeout: timeout }
132
+ end
133
+
134
+ # Syntactical sugar for making GET requests via the API.
135
+ # @see #execute
136
+ def get(path: nil, headers: {}, query: {}, auth_method: nil)
137
+ execute(method: :get, path: path, query: query, headers: headers, auth_method: auth_method)
138
+ end
139
+
140
+ # Syntactical sugar for making POST requests via the API.
141
+ # @see #execute
142
+ def post(path: nil, payload: nil, headers: {}, query: {}, auth_method: nil)
143
+ execute(
144
+ method: :post,
145
+ path: path,
146
+ headers: headers,
147
+ query: query,
148
+ payload: payload,
149
+ auth_method: auth_method
150
+ )
151
+ end
152
+
153
+ # Syntactical sugar for making PUT requests via the API.
154
+ # @see #execute
155
+ def put(path: nil, payload:, headers: {}, query: {}, auth_method: nil)
156
+ execute(
157
+ method: :put,
158
+ path: path,
159
+ headers: headers,
160
+ query: query,
161
+ payload: payload,
162
+ auth_method: auth_method
163
+ )
164
+ end
165
+
166
+ # Syntactical sugar for making DELETE requests via the API.
167
+ # @see #execute
168
+ def delete(path: nil, payload: nil, headers: {}, query: {}, auth_method: nil)
169
+ execute(
170
+ method: :delete,
171
+ path: path,
172
+ headers: headers,
173
+ query: query,
174
+ payload: payload,
175
+ auth_method: auth_method
176
+ )
177
+ end
178
+
179
+ def default_headers
180
+ @default_headers ||= {
181
+ "X-Nylas-API-Wrapper" => "ruby",
182
+ "X-Nylas-Client-Id" => @app_id,
183
+ "Nylas-API-Version" => SUPPORTED_API_VERSION,
184
+ "User-Agent" => "Nylas Ruby SDK #{NylasLegacy::VERSION} - #{RUBY_VERSION}",
185
+ "Content-type" => "application/json",
186
+ "Accept" => "application/json"
187
+ }
188
+ end
189
+
190
+ def parse_response(response)
191
+ return response if response.is_a?(Enumerable)
192
+
193
+ Yajl::Parser.new(symbolize_names: true).parse(response)
194
+ rescue Yajl::ParseError
195
+ raise NylasLegacy::JsonParseError
196
+ end
197
+ inform_on :parse_response, level: :debug, also_log: { result: true }
198
+
199
+ def url_for_path(path)
200
+ protocol, domain = api_server.split("//")
201
+ "#{protocol}//#{access_token}:@#{domain}#{path}"
202
+ end
203
+
204
+ private
205
+
206
+ def rest_client_execute(method:, url:, headers:, payload:, timeout:, &block)
207
+ ::RestClient::Request.execute(method: method, url: url, payload: payload,
208
+ headers: headers, timeout: timeout, &block)
209
+ end
210
+
211
+ inform_on :rest_client_execute, level: :debug,
212
+ also_log: { result: true, values: %i[method url headers payload] }
213
+
214
+ def handle_failed_response(result:, response:)
215
+ http_code = result.code.to_i
216
+
217
+ handle_anticipated_failure_mode(http_code: http_code, response: response)
218
+ raise UnexpectedResponse, result.msg if result.is_a?(Net::HTTPClientError)
219
+ end
220
+
221
+ def handle_anticipated_failure_mode(http_code:, response:)
222
+ return if HTTP_SUCCESS_CODES.include?(http_code)
223
+
224
+ exception = HTTP_CODE_TO_EXCEPTIONS.fetch(http_code, APIError)
225
+ case response
226
+ when Hash
227
+ raise error_hash_to_exception(exception, response)
228
+ when RestClient::Response
229
+ raise exception.parse_error_response(response)
230
+ else
231
+ raise exception.new(http_code, response)
232
+ end
233
+ end
234
+
235
+ def error_hash_to_exception(exception, response)
236
+ exception.new(
237
+ response[:type],
238
+ response[:message],
239
+ response.fetch(:server_error, nil)
240
+ )
241
+ end
242
+
243
+ def add_query_params_to_url(url, query)
244
+ unless query.empty?
245
+ uri = URI.parse(url)
246
+ query = custom_params(query)
247
+ params = URI.decode_www_form(uri.query || "") + query.to_a
248
+ uri.query = URI.encode_www_form(params)
249
+ url = uri.to_s
250
+ end
251
+
252
+ url
253
+ end
254
+
255
+ def custom_params(query)
256
+ # Convert hash to "<key>:<value>" form for metadata_pair query
257
+ if query.key?(:metadata_pair)
258
+ pairs = query[:metadata_pair].map do |key, value|
259
+ "#{key}:#{value}"
260
+ end
261
+ query[:metadata_pair] = pairs
262
+ end
263
+
264
+ query
265
+ end
266
+
267
+ def auth_header(auth_method)
268
+ authorization_string = case auth_method
269
+ when AuthMethod::BEARER
270
+ "Bearer #{access_token}"
271
+ when AuthMethod::BASIC
272
+ "Basic #{Base64.encode64("#{access_token}:")}"
273
+ else
274
+ "Bearer #{access_token}"
275
+ end
276
+
277
+ { "Authorization" => authorization_string }
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Structure to represent the IM Address Schema
5
+ # @see https://docs.nylas.com/reference#contactsid
6
+ class IMAddress
7
+ include Model::Attributable
8
+ attribute :type, :string
9
+ attribute :im_address, :string
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Ruby representation of a Nylas Job Status object
5
+ # @see https://developer.nylas.com/docs/api/#tag--Job-Status
6
+ class JobStatus
7
+ include Model
8
+ self.resources_path = "/job-statuses"
9
+ self.listable = true
10
+
11
+ attribute :id, :string, read_only: true
12
+ attribute :account_id, :string, read_only: true
13
+ attribute :job_status_id, :string, read_only: true
14
+ attribute :action, :string, read_only: true
15
+ attribute :object, :string, read_only: true
16
+ attribute :status, :string, read_only: true
17
+ attribute :created_at, :unix_timestamp, read_only: true
18
+ attribute :reason, :string, read_only: true
19
+ attribute :metadata, :hash, read_only: true
20
+
21
+ # Returns the status of a job as a boolean
22
+ # @return [Boolean] If the job was successful
23
+ def successful?
24
+ status == "successful"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Additional methods for some of Calendar's other functionality
5
+ # @see https://developer.nylas.com/docs/connectivity/calendar
6
+ class JobStatusCollection < Collection
7
+ def find_model(id)
8
+ response = api.execute(
9
+ **to_be_executed.merge(
10
+ path: "#{resources_path}/#{id}",
11
+ query: view_query
12
+ )
13
+ )
14
+
15
+ object_type = response[:object]
16
+ return OutboxJobStatus.from_hash(response, api: api) if object_type == "message"
17
+
18
+ model.from_hash(response, api: api)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Structure to represent the Label Schema
5
+ # @see https://docs.nylas.com/reference#labels
6
+ class Label
7
+ include Model
8
+ self.resources_path = "/labels"
9
+ self.creatable = true
10
+ self.listable = true
11
+ self.showable = true
12
+ self.filterable = false
13
+ self.updatable = true
14
+ self.destroyable = true
15
+ self.id_listable = true
16
+ self.countable = true
17
+
18
+ attribute :id, :string
19
+ attribute :account_id, :string
20
+ attribute :object, :string
21
+
22
+ attribute :name, :string
23
+ attribute :display_name, :string
24
+ attribute :provider_id, :string
25
+ attribute :job_status_id, :string, read_only: true
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "informed"
5
+ rescue LoadError
6
+ end
7
+
8
+ module NylasLegacy
9
+ # Exposes a shared logger for debugging purposes
10
+ module Logging
11
+ def self.included(object)
12
+ if const_defined? :Informed
13
+ object.include Informed
14
+ Informed.logger = logger
15
+ else
16
+ object.extend NoOpInformOn
17
+ end
18
+ end
19
+
20
+ def self.logger
21
+ return @logger if @logger
22
+
23
+ @logger = Logger.new(STDOUT)
24
+ @logger.level = level
25
+ @logger
26
+ end
27
+
28
+ def self.level
29
+ Logger.const_get(ENV["NYLAS_LOG_LEVEL"] || :WARN)
30
+ end
31
+
32
+ def self.logger=(logger)
33
+ @logger = logger
34
+ end
35
+
36
+ # No op for inform_on if user does not have the informed gem installed.
37
+ module NoOpInformOn
38
+ def inform_on(method, level: :debug, also_log: {}); end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Ruby representatin of a Nylas Message object
5
+ # @see https://docs.nylas.com/reference#messages
6
+ class Message
7
+ include Model
8
+ self.raw_mime_type = "message/rfc822"
9
+ self.resources_path = "/messages"
10
+ self.listable = true
11
+ self.showable = true
12
+ self.filterable = true
13
+ self.updatable = true
14
+ self.searchable = true
15
+ self.id_listable = true
16
+ self.countable = true
17
+ UPDATABLE_ATTRIBUTES = %i[label_ids folder_id starred unread metadata].freeze
18
+
19
+ attribute :id, :string
20
+ attribute :object, :string
21
+ attribute :account_id, :string
22
+ attribute :thread_id, :string
23
+
24
+ attribute :headers, :message_headers
25
+
26
+ has_n_of_attribute :to, :email_address
27
+ has_n_of_attribute :from, :email_address
28
+ has_n_of_attribute :cc, :email_address
29
+ has_n_of_attribute :bcc, :email_address
30
+ has_n_of_attribute :reply_to, :email_address
31
+
32
+ attribute :date, :unix_timestamp
33
+ # This is only used when receiving a message received notification via a webhook
34
+ attribute :received_date, :unix_timestamp
35
+ attribute :subject, :string
36
+ attribute :snippet, :string
37
+ attribute :body, :string
38
+ attribute :starred, :boolean
39
+ attribute :unread, :boolean
40
+
41
+ has_n_of_attribute :events, :event
42
+ has_n_of_attribute :files, :file
43
+ attribute :folder, :folder
44
+ attribute :folder_id, :string
45
+ attribute :metadata, :hash
46
+ attribute :reply_to_message_id, :string, read_only: true
47
+ attribute :job_status_id, :string, read_only: true
48
+
49
+ has_n_of_attribute :labels, :label, read_only: true
50
+ has_n_of_attribute :label_ids, :string
51
+
52
+ transfer :api, to: %i[events files folder labels]
53
+
54
+ def starred?
55
+ starred
56
+ end
57
+
58
+ def unread?
59
+ unread
60
+ end
61
+
62
+ def update(payload)
63
+ FilterAttributes.new(
64
+ attributes: payload.keys,
65
+ allowed_attributes: UPDATABLE_ATTRIBUTES
66
+ ).check
67
+
68
+ super(**payload)
69
+ end
70
+
71
+ def update_folder(folder_id)
72
+ update(folder_id: folder_id)
73
+ end
74
+
75
+ def expanded
76
+ return self unless headers.nil?
77
+
78
+ assign(**api.execute(method: :get, path: resource_path, query: { view: "expanded" }))
79
+ # Transfer reference to the API to attributes that need it
80
+ transfer_attributes
81
+ self
82
+ end
83
+
84
+ def save
85
+ handle_folder
86
+
87
+ super
88
+ end
89
+
90
+ def handle_folder
91
+ return if folder.nil?
92
+
93
+ self.folder_id = folder.id if folder_id.nil? && !self.to_h.dig(:folder, :id).nil?
94
+
95
+ self.folder = nil
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Translates message headers into a Ruby object
5
+ # @see https://docs.nylas.com/reference#section-message-views
6
+ class MessageHeaders
7
+ include Model::Attributable
8
+ attribute :in_reply_to, :string
9
+ attribute :message_id, :string
10
+ has_n_of_attribute :references, :string
11
+ end
12
+
13
+ # Serializes, Deserializes between {MessageHeaders} objects and a Hash
14
+ class MessageHeadersType < Types::ModelType
15
+ def initialize
16
+ super(model: MessageHeaders)
17
+ end
18
+ RUBY_KEY_TO_JSON_KEY_MAP = {
19
+ in_reply_to: :"In-Reply-To",
20
+ message_id: :"Message-Id",
21
+ references: :References
22
+ }.freeze
23
+ def json_key_from_attribute_name(attribute_name)
24
+ RUBY_KEY_TO_JSON_KEY_MAP.fetch(attribute_name)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ # Message tracking features
5
+ # @see https://docs.nylas.com/reference#message-tracking-overview
6
+ class MessageTracking
7
+ include Model::Attributable
8
+ attribute :links, :boolean
9
+ attribute :opens, :boolean
10
+ attribute :thread_replies, :boolean
11
+ attribute :payload, :string
12
+ end
13
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ module Model
5
+ # Allows defining of typecastable attributes on a model
6
+ module Attributable
7
+ def self.included(model)
8
+ model.extend(ClassMethods)
9
+ end
10
+
11
+ def initialize(**initial_data)
12
+ assign(**initial_data)
13
+ end
14
+
15
+ def attributes
16
+ @attributes ||= Attributes.new(self.class.attribute_definitions)
17
+ end
18
+
19
+ # @return [Hash] Representation of the model with values serialized into primitives based on their Type
20
+ def to_h(enforce_read_only: false)
21
+ attributes.to_h(enforce_read_only: enforce_read_only)
22
+ end
23
+
24
+ protected
25
+
26
+ def assign(**data)
27
+ data.each do |attribute_name, value|
28
+ next if value.nil?
29
+
30
+ if respond_to?(:"#{attribute_name}=")
31
+ send(:"#{attribute_name}=", value)
32
+ end
33
+ end
34
+ end
35
+
36
+ # Methods to call when tweaking Attributable classes
37
+ module ClassMethods
38
+ # rubocop:disable Naming/PredicateName
39
+ def has_n_of_attribute(name, type_name, read_only: false, default: [])
40
+ attribute_definitions[name] = ListAttributeDefinition.new(
41
+ type_name: type_name,
42
+ read_only: read_only,
43
+ default: default
44
+ )
45
+ define_accessors(name)
46
+ end
47
+ # rubocop:enable Naming/PredicateName
48
+
49
+ def attribute(name, type_name, read_only: false, default: nil)
50
+ attribute_definitions[name] = AttributeDefinition.new(
51
+ type_name: type_name,
52
+ read_only: read_only,
53
+ default: default
54
+ )
55
+ define_accessors(name)
56
+ end
57
+
58
+ def define_accessors(name)
59
+ define_method :"#{name}" do
60
+ attributes[name]
61
+ end
62
+
63
+ define_method :"#{name}=" do |value|
64
+ attributes[name] = value
65
+ end
66
+ end
67
+
68
+ # Allows a class to inherit parent's attributes
69
+ def inherit_attributes
70
+ return if superclass.nil?
71
+
72
+ parent_attributes = superclass.attribute_definitions
73
+ parent_attributes.each do |parent_attribute|
74
+ name = parent_attribute[0]
75
+ attr = parent_attribute[1]
76
+ next if attribute_definitions.key?(name)
77
+
78
+ attribute_definitions[name] = attr
79
+ define_accessors(name)
80
+ end
81
+ end
82
+
83
+ def attribute_definitions
84
+ @attribute_definitions ||= Registry.new
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NylasLegacy
4
+ module Model
5
+ # Define a particular attribute for a given model
6
+ class AttributeDefinition
7
+ extend Forwardable
8
+ def_delegators :type, :cast, :serialize, :serialize_for_api
9
+ attr_accessor :type_name, :read_only, :default
10
+
11
+ def initialize(type_name:, read_only:, default:)
12
+ self.type_name = type_name
13
+ self.read_only = read_only
14
+ self.default = default
15
+ end
16
+
17
+ private
18
+
19
+ def type
20
+ Types.registry[type_name]
21
+ end
22
+ end
23
+ end
24
+ end