nylas 5.0.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82a2a7e6af812dd58557c604deb553e18d586c373ee8c308b1eddc8492a44c28
4
- data.tar.gz: 43b9a7943a854c10f2257d49220fc420ff4e3b022b76a527ba772041600d24dd
3
+ metadata.gz: 9e585c607f124440a448e29f36d010eff7ac9b2023000b82256874830338f327
4
+ data.tar.gz: 0c0d882e1831a5367f4eaa69701482c6b452cf129e205a136def8f64310b695e
5
5
  SHA512:
6
- metadata.gz: 6c005ca3d6e0f61bc25ebdab118cc0dda5dd366c24b8ad1519b78a5bb32bd0de976b1070fb6dc35dfbd81ffd4540c636956c38f1248e412e80441cf12fb788d0
7
- data.tar.gz: 05e47ffa2fb00e66adf7483b7eb7a0bd870c85dbff006dee3cfa7b968589173634d77d74519bc04e657d214efdfd17b1bc8ef492da0880edef5552fb012ac466
6
+ metadata.gz: 2cf81593d36344ca0f18e734688fa6276acc86be3ffa0436bc0e02aa126414f920e7295ab0de1ce8f90538505073ae180ce1e94bcb1255c37aa471c06aad63cd
7
+ data.tar.gz: 47d5ebabda297aeca2d455536ce12eb7292c895a4865b815173f4852f24d131583709127c5549b15ca1d3a1999582090198be23ea72a9fdd41fe5bac9d675509
data/lib/nylas/api.rb CHANGED
@@ -16,13 +16,11 @@ module Nylas
16
16
  # @param access_token [String] (Optional) Your users access token.
17
17
  # @param api_server [String] (Optional) Which Nylas API Server to connect to. Only change this if
18
18
  # you're using a self-hosted Nylas instance.
19
- # @param service_domain [String] (Optional) Host you are authenticating OAuth against.
20
19
  # @return [Nylas::API]
21
20
  def initialize(client: nil, app_id: nil, app_secret: nil, access_token: nil,
22
- api_server: "https://api.nylas.com", service_domain: "api.nylas.com")
21
+ api_server: "https://api.nylas.com")
23
22
  self.client = client || HttpClient.new(app_id: app_id, app_secret: app_secret,
24
- access_token: access_token, api_server: api_server,
25
- service_domain: service_domain)
23
+ access_token: access_token, api_server: api_server)
26
24
  end
27
25
 
28
26
  # @return [String] A Nylas access token for that particular user.
@@ -123,6 +121,16 @@ module Nylas
123
121
  @messages ||= Collection.new(model: Message, api: self)
124
122
  end
125
123
 
124
+ # @return[Collection<RoomResource>] A queryable collection of {RoomResource} objects
125
+ def room_resources
126
+ @room_resources ||= Collection.new(model: RoomResource, api: self)
127
+ end
128
+
129
+ # @return[Neural] A {Neural} object that provides
130
+ def neural
131
+ @neural ||= Neural.new(api: self)
132
+ end
133
+
126
134
  # Revokes access to the Nylas API for the given access token
127
135
  # @return [Boolean]
128
136
  def revoke(access_token)
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the Neural Categorize object.
5
+ # @see https://developer.nylas.com/docs/intelligence/categorizer/#categorize-message-response
6
+ class Categorize
7
+ include Model::Attributable
8
+
9
+ attribute :category, :string
10
+ attribute :categorized_at, :unix_timestamp
11
+ attribute :model_version, :string
12
+ has_n_of_attribute :subcategories, :string
13
+ end
14
+ end
data/lib/nylas/contact.rb CHANGED
@@ -13,9 +13,9 @@ module Nylas
13
13
  self.updatable = true
14
14
  self.destroyable = true
15
15
 
16
- attribute :id, :string, exclude_when: %i[creating updating]
16
+ attribute :id, :string, read_only: true
17
17
  attribute :object, :string, default: "contact"
18
- attribute :account_id, :string, exclude_when: %i[creating updating]
18
+ attribute :account_id, :string, read_only: true
19
19
 
20
20
  attribute :given_name, :string
21
21
  attribute :middle_name, :string
data/lib/nylas/delta.rb CHANGED
@@ -6,6 +6,7 @@ module Nylas
6
6
  # @see https://docs.nylas.com/reference#deltas
7
7
  class Delta
8
8
  include Model::Attributable
9
+
9
10
  attribute :id, :string
10
11
  attribute :type, :string
11
12
  attribute :object, :string
@@ -14,6 +15,8 @@ module Nylas
14
15
  attribute :namespace_id, :string
15
16
  attribute :account_id, :string
16
17
 
18
+ attribute :headers, :message_headers
19
+
17
20
  attribute :date, :unix_timestamp
18
21
  attribute :metadata, :hash
19
22
  attribute :object_attributes, :hash
@@ -24,6 +27,8 @@ module Nylas
24
27
  @model ||= Types.registry[object.to_sym].cast(object_attributes_with_ids)
25
28
  end
26
29
 
30
+ private
31
+
27
32
  def object_attributes_with_ids
28
33
  (object_attributes || {}).merge(id: id, account_id: account_id)
29
34
  end
@@ -42,8 +47,10 @@ module Nylas
42
47
  else
43
48
  data
44
49
  end
50
+
51
+ data = data.merge(data[:attributes]) if data[:attributes]
45
52
  data[:object_attributes] = data.delete(:attributes)
46
- super(data)
53
+ super(**data)
47
54
  end
48
55
  end
49
56
  end
data/lib/nylas/deltas.rb CHANGED
@@ -14,6 +14,6 @@ module Nylas
14
14
  attribute :cursor_end, :string
15
15
 
16
16
  extend Forwardable
17
- def_delegators :deltas, :count, :length, :each, :map, :first, :to_a, :empty?
17
+ def_delegators :deltas, :count, :length, :each, :map, :first, :last, :to_a, :empty?
18
18
  end
19
19
  end
data/lib/nylas/draft.rb CHANGED
@@ -29,7 +29,8 @@ module Nylas
29
29
  attribute :unread, :boolean
30
30
 
31
31
  has_n_of_attribute :events, :event
32
- has_n_of_attribute :files, :file
32
+ has_n_of_attribute :files, :file, read_only: true
33
+ has_n_of_attribute :file_ids, :string
33
34
  attribute :folder, :folder
34
35
  has_n_of_attribute :labels, :label
35
36
 
@@ -37,10 +38,26 @@ module Nylas
37
38
 
38
39
  transfer :api, to: %i[events files folder labels]
39
40
 
41
+ def update(**data)
42
+ # If files are provided, replace files with file IDs
43
+ self.files = data[:files] if data[:files]
44
+ extract_file_ids!
45
+ data[:file_ids] = file_ids
46
+ # If version is not provided, add version or request will fail
47
+ data[:version] = version unless data[:version]
48
+
49
+ super
50
+ end
51
+
52
+ def create
53
+ extract_file_ids!
54
+
55
+ super
56
+ end
57
+
40
58
  def send!
41
- return execute(method: :post, path: "/send", payload: to_json) if tracking
59
+ return execute(method: :post, path: "/send", payload: to_json) if tracking || !id
42
60
 
43
- save
44
61
  execute(method: :post, path: "/send", payload: JSON.dump(draft_id: id, version: version))
45
62
  end
46
63
 
@@ -53,7 +70,21 @@ module Nylas
53
70
  end
54
71
 
55
72
  def destroy
56
- execute(method: :delete, path: resource_path, payload: attributes.serialize(keys: [:version]))
73
+ execute(method: :delete, path: resource_path, payload: attributes.serialize_for_api(keys: [:version]))
74
+ end
75
+
76
+ private
77
+
78
+ def save_call
79
+ extract_file_ids!
80
+
81
+ super
82
+ end
83
+
84
+ def extract_file_ids!
85
+ files = self.files || []
86
+
87
+ self.file_ids = files.map(&:id)
57
88
  end
58
89
  end
59
90
  end
data/lib/nylas/event.rb CHANGED
@@ -9,9 +9,9 @@ module Nylas
9
9
  allows_operations(creatable: true, listable: true, filterable: true, showable: true, updatable: true,
10
10
  destroyable: true)
11
11
 
12
- attribute :id, :string, exclude_when: %i[saving]
13
- attribute :object, :string, exclude_when: %i[saving]
14
- attribute :account_id, :string, exclude_when: %i[saving]
12
+ attribute :id, :string, read_only: true
13
+ attribute :object, :string, read_only: true
14
+ attribute :account_id, :string, read_only: true
15
15
  attribute :calendar_id, :string
16
16
  attribute :master_event_id, :string
17
17
  attribute :message_id, :string
@@ -27,6 +27,8 @@ module Nylas
27
27
  attribute :status, :string
28
28
  attribute :title, :string
29
29
  attribute :when, :when
30
+ attribute :metadata, :hash
31
+ attribute :conferencing, :event_conferencing
30
32
  attribute :original_start_time, :unix_timestamp
31
33
 
32
34
  attr_accessor :notify_participants
@@ -39,6 +41,17 @@ module Nylas
39
41
  read_only
40
42
  end
41
43
 
44
+ def save
45
+ if conferencing
46
+ body = to_h
47
+ if body.dig(:conferencing, :details) && body.dig(:conferencing, :autocreate)
48
+ raise ArgumentError, "Cannot set both 'details' and 'autocreate' in conferencing object."
49
+ end
50
+ end
51
+
52
+ super
53
+ end
54
+
42
55
  def rsvp(status, notify_participants:)
43
56
  rsvp = Rsvp.new(api: api, status: status, notify_participants: notify_participants,
44
57
  event_id: id, account_id: account_id)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the Event Conferencing object
5
+ # @see https://developer.nylas.com/docs/connectivity/calendar/conference-sync-beta
6
+ class EventConferencing
7
+ include Model::Attributable
8
+ attribute :provider, :string
9
+ attribute :details, :event_conferencing_details
10
+ attribute :autocreate, :event_conferencing_autocreate
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the autocreate object within the Event Conferencing object
5
+ # @see https://developer.nylas.com/docs/connectivity/calendar/conference-sync-beta
6
+ class EventConferencingAutocreate
7
+ include Model::Attributable
8
+ attribute :settings, :hash, default: {}
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the details object within the Event Conferencing object
5
+ # @see https://developer.nylas.com/docs/connectivity/calendar/conference-sync-beta
6
+ class EventConferencingDetails
7
+ include Model::Attributable
8
+ attribute :meeting_code, :string
9
+ attribute :password, :string
10
+ attribute :pin, :string
11
+ attribute :url, :string
12
+ has_n_of_attribute :phone, :string
13
+ end
14
+ end
@@ -5,6 +5,8 @@ module Nylas
5
5
 
6
6
  # Plain HTTP client that can be used to interact with the Nylas API sans any type casting.
7
7
  class HttpClient # rubocop:disable Metrics/ClassLength
8
+ HTTP_SUCCESS_CODES = [200, 201, 302].freeze
9
+
8
10
  HTTP_CODE_TO_EXCEPTIONS = {
9
11
  400 => InvalidRequest,
10
12
  401 => UnauthorizedRequest,
@@ -34,7 +36,7 @@ module Nylas
34
36
  SUPPORTED_API_VERSION = "2.2"
35
37
 
36
38
  include Logging
37
- attr_accessor :api_server, :service_domain
39
+ attr_accessor :api_server
38
40
  attr_writer :default_headers
39
41
  attr_reader :access_token
40
42
  attr_reader :app_id
@@ -45,10 +47,8 @@ module Nylas
45
47
  # @param access_token [String] (Optional) Your users access token.
46
48
  # @param api_server [String] (Optional) Which Nylas API Server to connect to. Only change this if
47
49
  # you're using a self-hosted Nylas instance.
48
- # @param service_domain [String] (Optional) Host you are authenticating OAuth against.
49
50
  # @return [Nylas::HttpClient]
50
- def initialize(app_id:, app_secret:, access_token: nil, api_server: "https://api.nylas.com",
51
- service_domain: "api.nylas.com")
51
+ def initialize(app_id:, app_secret:, access_token: nil, api_server: "https://api.nylas.com")
52
52
  unless api_server.include?("://")
53
53
  raise "When overriding the Nylas API server address, you must include https://"
54
54
  end
@@ -57,13 +57,12 @@ module Nylas
57
57
  @access_token = access_token
58
58
  @app_secret = app_secret
59
59
  @app_id = app_id
60
- @service_domain = service_domain
61
60
  end
62
61
 
63
62
  # @return [Nylas::HttpClient[]
64
63
  def as(access_token)
65
64
  HttpClient.new(app_id: app_id, access_token: access_token,
66
- app_secret: app_secret, api_server: api_server, service_domain: service_domain)
65
+ app_secret: app_secret, api_server: api_server)
67
66
  end
68
67
 
69
68
  # Sends a request to the Nylas API and rai
@@ -93,7 +92,12 @@ module Nylas
93
92
  content_type = response.headers[:content_type].downcase
94
93
  end
95
94
 
96
- response = parse_response(response) if content_type == "application/json"
95
+ begin
96
+ response = parse_response(response) if content_type == "application/json"
97
+ rescue Nylas::JsonParseError
98
+ handle_failed_response(result: result, response: response)
99
+ raise
100
+ end
97
101
 
98
102
  handle_failed_response(result: result, response: response)
99
103
  response
@@ -104,8 +108,8 @@ module Nylas
104
108
  also_log: { result: true, values: %i[method url path headers query payload] }
105
109
 
106
110
  def build_request(method:, path: nil, headers: {}, query: {}, payload: nil, timeout: nil)
107
- headers[:params] = query
108
111
  url ||= url_for_path(path)
112
+ url = add_query_params_to_url(url, query)
109
113
  resulting_headers = default_headers.merge(headers)
110
114
  { method: method, url: url, payload: payload, headers: resulting_headers, timeout: timeout }
111
115
  end
@@ -140,7 +144,7 @@ module Nylas
140
144
  "X-Nylas-Client-Id" => @app_id,
141
145
  "Nylas-API-Version" => SUPPORTED_API_VERSION,
142
146
  "User-Agent" => "Nylas Ruby SDK #{Nylas::VERSION} - #{RUBY_VERSION}",
143
- "Content-types" => "application/json"
147
+ "Content-type" => "application/json"
144
148
  }
145
149
  end
146
150
 
@@ -177,11 +181,40 @@ module Nylas
177
181
  end
178
182
 
179
183
  def handle_anticipated_failure_mode(http_code:, response:)
180
- return if http_code == 200
181
- return unless response.is_a?(Hash)
184
+ return if HTTP_SUCCESS_CODES.include?(http_code)
182
185
 
183
186
  exception = HTTP_CODE_TO_EXCEPTIONS.fetch(http_code, APIError)
184
- raise exception.new(response[:type], response[:message], response.fetch(:server_error, nil))
187
+ raise exception.new(http_code, response) unless response.is_a?(Hash)
188
+
189
+ raise exception.new(
190
+ response[:type],
191
+ response[:message],
192
+ response.fetch(:server_error, nil)
193
+ )
194
+ end
195
+
196
+ def add_query_params_to_url(url, query)
197
+ unless query.empty?
198
+ uri = URI.parse(url)
199
+ query = custom_params(query)
200
+ params = URI.decode_www_form(uri.query || "") + query.to_a
201
+ uri.query = URI.encode_www_form(params)
202
+ url = uri.to_s
203
+ end
204
+
205
+ url
206
+ end
207
+
208
+ def custom_params(query)
209
+ # Convert hash to "<key>:<value>" form for metadata_pair query
210
+ if query.key?(:metadata_pair)
211
+ pairs = query[:metadata_pair].map do |key, value|
212
+ "#{key}:#{value}"
213
+ end
214
+ query[:metadata_pair] = pairs
215
+ end
216
+
217
+ query
185
218
  end
186
219
  end
187
220
  end
data/lib/nylas/message.rb CHANGED
@@ -37,7 +37,7 @@ module Nylas
37
37
  attribute :folder, :folder
38
38
  attribute :folder_id, :string
39
39
 
40
- has_n_of_attribute :labels, :label, exclude_when: [:saving]
40
+ has_n_of_attribute :labels, :label, read_only: true
41
41
  has_n_of_attribute :label_ids, :string
42
42
 
43
43
  transfer :api, to: %i[events files folder labels]
@@ -67,6 +67,8 @@ module Nylas
67
67
  return self unless headers.nil?
68
68
 
69
69
  assign(**api.execute(method: :get, path: resource_path, query: { view: "expanded" }))
70
+ # Transfer reference to the API to attributes that need it
71
+ transfer_attributes
70
72
  self
71
73
  end
72
74
 
@@ -75,7 +77,7 @@ module Nylas
75
77
 
76
78
  execute(
77
79
  method: :put,
78
- payload: attributes.serialize(keys: allowed_keys_for_save),
80
+ payload: attributes.serialize_for_api,
79
81
  path: resource_path
80
82
  )
81
83
  end
@@ -25,6 +25,8 @@ module Nylas
25
25
 
26
26
  def assign(**data)
27
27
  data.each do |attribute_name, value|
28
+ next if value.nil?
29
+
28
30
  if respond_to?(:"#{attribute_name}=")
29
31
  send(:"#{attribute_name}=", value)
30
32
  end
@@ -34,17 +36,22 @@ module Nylas
34
36
  # Methods to call when tweaking Attributable classes
35
37
  module ClassMethods
36
38
  # rubocop:disable Naming/PredicateName
37
- def has_n_of_attribute(name, type_name, exclude_when: [], default: [])
38
- attribute_definitions[name] = ListAttributeDefinition.new(type_name: type_name,
39
- exclude_when: exclude_when,
40
- default: default)
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
+ )
41
45
  define_accessors(name)
42
46
  end
43
47
  # rubocop:enable Naming/PredicateName
44
48
 
45
- def attribute(name, type_name, exclude_when: [], default: nil)
46
- attribute_definitions[name] = AttributeDefinition.new(type_name: type_name,
47
- exclude_when: exclude_when, default: default)
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
+ )
48
55
  define_accessors(name)
49
56
  end
50
57
 
@@ -58,6 +65,21 @@ module Nylas
58
65
  end
59
66
  end
60
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
+
61
83
  def attribute_definitions
62
84
  @attribute_definitions ||= Registry.new
63
85
  end
@@ -6,11 +6,11 @@ module Nylas
6
6
  class AttributeDefinition
7
7
  extend Forwardable
8
8
  def_delegators :type, :cast, :serialize
9
- attr_accessor :type_name, :exclude_when, :default
9
+ attr_accessor :type_name, :read_only, :default
10
10
 
11
- def initialize(type_name:, exclude_when:, default:)
11
+ def initialize(type_name:, read_only:, default:)
12
12
  self.type_name = type_name
13
- self.exclude_when = exclude_when
13
+ self.read_only = read_only
14
14
  self.default = default
15
15
  end
16
16
 
@@ -31,7 +31,9 @@ module Nylas
31
31
  def to_h(keys: attribute_definitions.keys)
32
32
  keys.each_with_object({}) do |key, casted_data|
33
33
  value = attribute_definitions[key].serialize(self[key])
34
- casted_data[key] = value unless value.nil? || (value.respond_to?(:empty?) && value.empty?)
34
+ # If the value is an empty hash but we specify that it is valid (via default value), serialize it
35
+ casted_data[key] = value unless value.nil? || (value.respond_to?(:empty?) && value.empty? &&
36
+ !(attribute_definitions[key].default == value && value.is_a?(Hash)))
35
37
  end
36
38
  end
37
39
 
@@ -39,6 +41,22 @@ module Nylas
39
41
  JSON.dump(to_h(keys: keys))
40
42
  end
41
43
 
44
+ def serialize_for_api(keys: attribute_definitions.keys)
45
+ api_keys = keys.delete_if { |key| attribute_definitions[key].read_only == true }
46
+
47
+ serialize(keys: api_keys)
48
+ end
49
+
50
+ def serialize_all_for_api(keys: attribute_definitions.keys)
51
+ api_keys = keys.delete_if { |key| attribute_definitions[key].read_only == true }
52
+
53
+ JSON.dump(
54
+ api_keys.each_with_object({}) do |key, casted_data|
55
+ casted_data[key] = attribute_definitions[key].serialize(self[key])
56
+ end
57
+ )
58
+ end
59
+
42
60
  private
43
61
 
44
62
  def cast(key, value)
@@ -4,11 +4,11 @@ module Nylas
4
4
  module Model
5
5
  # Allows models to have an attribute which is a lists of another type of thing
6
6
  class ListAttributeDefinition
7
- attr_accessor :type_name, :exclude_when, :default
7
+ attr_accessor :type_name, :read_only, :default
8
8
 
9
- def initialize(type_name:, exclude_when:, default:)
9
+ def initialize(type_name:, read_only:, default:)
10
10
  self.type_name = type_name
11
- self.exclude_when = exclude_when
11
+ self.read_only = read_only
12
12
  self.default = default
13
13
  end
14
14
 
data/lib/nylas/model.rb CHANGED
@@ -48,7 +48,7 @@ module Nylas
48
48
 
49
49
  execute(
50
50
  method: :post,
51
- payload: attributes.serialize,
51
+ payload: attributes.serialize_for_api,
52
52
  path: resources_path,
53
53
  query: query_params
54
54
  )
@@ -58,12 +58,37 @@ module Nylas
58
58
  raise ModelNotUpdatableError, model_class unless updatable?
59
59
 
60
60
  attributes.merge(**data)
61
- execute(
62
- method: :put,
63
- payload: attributes.serialize(keys: data.keys),
64
- path: resource_path,
65
- query: query_params
66
- )
61
+ payload = attributes.serialize_for_api(keys: data.keys)
62
+ update_call(payload)
63
+
64
+ true
65
+ rescue Registry::MissingKeyError => e
66
+ raise ModelMissingFieldError.new(e.key, self)
67
+ end
68
+
69
+ def save_all_attributes
70
+ result = if persisted?
71
+ raise ModelNotUpdatableError, self unless updatable?
72
+
73
+ execute(
74
+ method: :put,
75
+ payload: attributes.serialize_all_for_api,
76
+ path: resource_path
77
+ )
78
+ else
79
+ create
80
+ end
81
+
82
+ attributes.merge(result)
83
+ end
84
+
85
+ def update_all_attributes(**data)
86
+ raise ModelNotUpdatableError, model_class unless updatable?
87
+
88
+ attributes.merge(**data)
89
+ payload = attributes.serialize_all_for_api(keys: data.keys)
90
+ update_call(payload)
91
+
67
92
  true
68
93
  rescue Registry::MissingKeyError => e
69
94
  raise ModelMissingFieldError.new(e.key, self)
@@ -95,20 +120,24 @@ module Nylas
95
120
 
96
121
  private
97
122
 
98
- def allowed_keys_for_save
99
- attributes.attribute_definitions.to_h.reject do |_k, v|
100
- v.exclude_when.include?(:saving)
101
- end.keys
102
- end
103
-
104
123
  def save_call
105
124
  execute(
106
125
  method: :put,
107
- payload: attributes.serialize(keys: allowed_keys_for_save),
126
+ payload: attributes.serialize_for_api,
108
127
  path: resource_path
109
128
  )
110
129
  end
111
130
 
131
+ def update_call(payload)
132
+ result = execute(
133
+ method: :put,
134
+ payload: payload,
135
+ path: resource_path,
136
+ query: query_params
137
+ )
138
+ attributes.merge(result) if result
139
+ end
140
+
112
141
  def query_params
113
142
  {}
114
143
  end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Class containing methods for accessing Neural API features.
5
+ # @see https://developer.nylas.com/docs/intelligence/
6
+ class Neural
7
+ attr_accessor :api
8
+
9
+ def initialize(api:)
10
+ self.api = api
11
+ end
12
+
13
+ def sentiment_analysis_message(message_ids)
14
+ body = { message_id: message_ids }
15
+ response = request(NeuralSentimentAnalysis.resources_path, body)
16
+
17
+ collection = []
18
+ response.each do |sentiment|
19
+ collection.push(NeuralSentimentAnalysis.new(**sentiment.merge(api: api)))
20
+ end
21
+ collection
22
+ end
23
+
24
+ def sentiment_analysis_text(text)
25
+ body = { text: text }
26
+ NeuralSentimentAnalysis.new(**request(NeuralSentimentAnalysis.resources_path, body).merge(api: api))
27
+ end
28
+
29
+ def extract_signature(message_ids, options = nil)
30
+ body = { message_id: message_ids }
31
+ body = body.merge(options) unless options.nil?
32
+ response = request(NeuralSignatureExtraction.resources_path, body)
33
+
34
+ collection = []
35
+ response.each do |signature|
36
+ collection.push(NeuralSignatureExtraction.new(**signature.merge(api: api)))
37
+ end
38
+ collection
39
+ end
40
+
41
+ def ocr_request(file_id, pages = nil)
42
+ body = { file_id: file_id }
43
+ body[:pages] = pages unless pages.nil?
44
+
45
+ NeuralOcr.new(**request(NeuralOcr.resources_path, body).merge(api: api))
46
+ end
47
+
48
+ def categorize(message_ids)
49
+ body = { message_id: message_ids }
50
+ response = request(NeuralCategorizer.resources_path, body)
51
+
52
+ collection = []
53
+ response.each do |categorize|
54
+ collection.push(NeuralCategorizer.new(**categorize.merge(api: api)))
55
+ end
56
+ collection
57
+ end
58
+
59
+ def clean_conversation(message_ids, options = nil)
60
+ body = { message_id: message_ids }
61
+ body = body.merge(delete_from_hash(options.to_hash, :parse_contact)) unless options.nil?
62
+
63
+ response = request(NeuralCleanConversation.resources_path, body)
64
+ collection = []
65
+ response.each do |conversation|
66
+ collection.push(NeuralCleanConversation.new(**conversation.merge(api: api)))
67
+ end
68
+ collection
69
+ end
70
+
71
+ private
72
+
73
+ def request(path, body)
74
+ api.execute(
75
+ method: :put,
76
+ path: path,
77
+ payload: JSON.dump(body)
78
+ )
79
+ end
80
+
81
+ # For Ruby < 3.0 support, as it doesn't support Hash.except
82
+ def delete_from_hash(hash, to_delete)
83
+ hash.delete(to_delete)
84
+ hash
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Neural Categorizer object.
5
+ # @see https://developer.nylas.com/docs/intelligence/categorizer/#categorize-message-response
6
+ class NeuralCategorizer < Message
7
+ include Model
8
+ self.resources_path = "/neural/categorize"
9
+ allows_operations(listable: true)
10
+
11
+ attribute :categorizer, :categorize
12
+ # Overrides Message's label attribute as currently categorize returns
13
+ # list of strings for labels instead of label object types
14
+ has_n_of_attribute :labels, :string
15
+
16
+ inherit_attributes
17
+
18
+ def recategorize(category)
19
+ body = { message_id: id, category: category }
20
+ api.execute(
21
+ method: :post,
22
+ path: "#{resources_path}/feedback",
23
+ payload: JSON.dump(body)
24
+ )
25
+ list = api.neural.categorize([id])
26
+ list[0]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Neural Clean Conversations object.
5
+ # @see https://developer.nylas.com/docs/intelligence/clean-conversations/#clean-conversation-response
6
+ class NeuralCleanConversation < Message
7
+ include Model
8
+ self.resources_path = "/neural/conversation"
9
+ allows_operations(listable: true)
10
+ IMAGE_REGEX = /[(']cid:(.*?)[)']/.freeze
11
+
12
+ attribute :conversation, :string
13
+ attribute :model_version, :string
14
+
15
+ inherit_attributes
16
+
17
+ # Parses image file IDs found in the clean conversation object and returns
18
+ # an array of File objects returned from the File API
19
+ def extract_images
20
+ return if conversation.nil?
21
+
22
+ files = []
23
+ matches = conversation.scan(IMAGE_REGEX)
24
+ matches.each do |match|
25
+ # After applying the regex, if there are IDs found they would be
26
+ # in the form of => 'cid:xxxx' (including apostrophes), so we discard
27
+ # everything before and after the file ID (denoted as xxxx above)
28
+ files.push(api.files.find(match))
29
+ end
30
+ files
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the "Link" object in the Neural API's Signature Extraction Contact object
5
+ # @see https://developer.nylas.com/docs/intelligence/signature-extraction/#parse-signature-response
6
+ class NeuralContactLink
7
+ include Model::Attributable
8
+ attribute :description, :string
9
+ attribute :url, :string
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the "Name" object in the Neural API's Signature Extraction Contact object
5
+ # @see https://developer.nylas.com/docs/intelligence/signature-extraction/#parse-signature-response
6
+ class NeuralContactName
7
+ include Model::Attributable
8
+ attribute :first_name, :string
9
+ attribute :last_name, :string
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Neural Optical Character Recognition object.
5
+ # @see https://developer.nylas.com/docs/intelligence/optical-charecter-recognition/#ocr-response
6
+ class NeuralMessageOptions
7
+ attr_accessor :ignore_links, :ignore_images, :ignore_tables, :remove_conclusion_phrases,
8
+ :images_as_markdown, :parse_contact
9
+
10
+ def initialize(ignore_links: nil,
11
+ ignore_images: nil,
12
+ ignore_tables: nil,
13
+ remove_conclusion_phrases: nil,
14
+ images_as_markdown: nil,
15
+ parse_contact: nil)
16
+ @ignore_links = ignore_links
17
+ @ignore_images = ignore_images
18
+ @ignore_tables = ignore_tables
19
+ @remove_conclusion_phrases = remove_conclusion_phrases
20
+ @images_as_markdown = images_as_markdown
21
+ @parse_contact = parse_contact
22
+ end
23
+
24
+ def to_hash
25
+ hash = {}
26
+ hash[:ignore_links] = @ignore_links unless @ignore_links.nil?
27
+ hash[:ignore_images] = @ignore_images unless @ignore_images.nil?
28
+ hash[:ignore_tables] = @ignore_tables unless @ignore_tables.nil?
29
+ hash[:remove_conclusion_phrases] = @remove_conclusion_phrases unless @remove_conclusion_phrases.nil?
30
+ hash[:images_as_markdown] = @images_as_markdown unless @images_as_markdown.nil?
31
+ hash[:parse_contact] = @parse_contact unless @parse_contact.nil?
32
+ hash
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Neural Optical Character Recognition object.
5
+ # @see https://developer.nylas.com/docs/intelligence/optical-charecter-recognition/#ocr-response
6
+ class NeuralOcr < File
7
+ include Model
8
+ self.resources_path = "/neural/ocr"
9
+ allows_operations(listable: true)
10
+
11
+ has_n_of_attribute :ocr, :string
12
+ attribute :processed_pages, :integer
13
+
14
+ inherit_attributes
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Neural Sentiment Analysis object.
5
+ # @see https://developer.nylas.com/docs/intelligence/sentiment-analysis/#sentiment-analysis-response-message
6
+ class NeuralSentimentAnalysis
7
+ include Model
8
+ self.resources_path = "/neural/sentiment"
9
+ allows_operations(listable: true)
10
+
11
+ attribute :account_id, :string
12
+ attribute :sentiment, :string
13
+ attribute :sentiment_score, :float
14
+ attribute :processed_length, :integer
15
+ attribute :text, :string
16
+ end
17
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the Neural API's Signature Extraction Contact object
5
+ # @see https://developer.nylas.com/docs/intelligence/signature-extraction/#parse-signature-response
6
+ class NeuralSignatureContact
7
+ include Model::Attributable
8
+ has_n_of_attribute :job_titles, :string
9
+ has_n_of_attribute :links, :neural_contact_link
10
+ has_n_of_attribute :phone_numbers, :string
11
+ has_n_of_attribute :emails, :string
12
+ has_n_of_attribute :names, :neural_contact_name
13
+
14
+ attr_accessor :api
15
+
16
+ # Creates a Nylas contact object compatible with the contact endpoints.
17
+ # Please note if multiple names or multiple job titles were parsed only
18
+ # the first set are used.
19
+ def to_contact_object
20
+ contact = merge_multiple_hashes([convert_names, convert_emails, convert_phone_numbers, convert_links])
21
+ contact[:job_title] = job_titles[0] unless job_titles.nil?
22
+ Contact.new(**contact.merge(api: api))
23
+ end
24
+
25
+ private
26
+
27
+ def convert_names
28
+ return {} if names.empty?
29
+
30
+ contact = {}
31
+ contact[:given_name] = names[0].first_name if names[0].first_name
32
+ contact[:surname] = names[0].last_name if names[0].last_name
33
+ contact
34
+ end
35
+
36
+ def convert_emails
37
+ return {} if emails.empty?
38
+
39
+ contact = {}
40
+ contact[:emails] = []
41
+ emails.each do |e|
42
+ contact[:emails].push(type: "personal", email: e)
43
+ end
44
+ contact
45
+ end
46
+
47
+ def convert_phone_numbers
48
+ return {} if phone_numbers.empty?
49
+
50
+ contact = {}
51
+ contact[:phone_numbers] = []
52
+ phone_numbers.each do |number|
53
+ contact[:phone_numbers].push(type: "mobile", number: number)
54
+ end
55
+ contact
56
+ end
57
+
58
+ def convert_links
59
+ return {} if links.empty?
60
+
61
+ contact = {}
62
+ contact[:web_pages] = []
63
+ links.each do |link|
64
+ type = "homepage"
65
+ type = link.description unless link.description.empty?
66
+ contact[:web_pages].push(type: type, url: link.url)
67
+ end
68
+ contact
69
+ end
70
+
71
+ # For Ruby 2.5 support as it doesn't support multiple hashes to merge at once
72
+ def merge_multiple_hashes(hashes_to_merge)
73
+ hash = {}
74
+ hashes_to_merge.each do |new_hash|
75
+ hash = hash.merge(new_hash)
76
+ end
77
+
78
+ hash
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Signature Extraction Schema.
5
+ # @see https://developer.nylas.com/docs/intelligence/signature-extraction/#signature-feedback-response
6
+ class NeuralSignatureExtraction < Message
7
+ include Model
8
+ self.resources_path = "/neural/signature"
9
+
10
+ attribute :signature, :string
11
+ attribute :model_version, :string
12
+ attribute :contacts, :neural_signature_contact
13
+
14
+ inherit_attributes
15
+
16
+ transfer :api, to: %i[contacts]
17
+ end
18
+ end
@@ -26,7 +26,7 @@ module Nylas
26
26
  attribute :tracking, :message_tracking
27
27
 
28
28
  def send!
29
- Message.new(api.execute(method: :post, path: "/send", payload: to_json).merge(api: api))
29
+ Message.new(**api.execute(method: :post, path: "/send", payload: to_json).merge(api: api))
30
30
  end
31
31
  end
32
32
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Ruby representation of a Nylas Room Resource object
5
+ # @see https://developer.nylas.com/docs/api/#tag--Room-Resources
6
+ class RoomResource
7
+ include Model
8
+ self.resources_path = "/resources"
9
+ allows_operations(listable: true)
10
+
11
+ attribute :object, :string, read_only: true
12
+ attribute :email, :string, read_only: true
13
+ attribute :name, :string, read_only: true
14
+ attribute :capacity, :string, read_only: true
15
+ attribute :building, :string, read_only: true
16
+ attribute :floor_name, :string, read_only: true
17
+ attribute :floor_number, :string, read_only: true
18
+ end
19
+ end
data/lib/nylas/rsvp.rb CHANGED
@@ -13,8 +13,12 @@ module Nylas
13
13
  attr_accessor :notify_participants
14
14
 
15
15
  def save
16
- api.execute(method: :post, path: "/send-rsvp", payload: attributes.serialize,
17
- query: { notify_participants: notify_participants })
16
+ api.execute(
17
+ method: :post,
18
+ path: "/send-rsvp",
19
+ payload: attributes.serialize_for_api,
20
+ query: { notify_participants: notify_participants }
21
+ )
18
22
  end
19
23
  end
20
24
  end
data/lib/nylas/thread.rb CHANGED
@@ -23,6 +23,7 @@ module Nylas
23
23
  has_n_of_attribute :labels, :label
24
24
  has_n_of_attribute :folders, :folder
25
25
  has_n_of_attribute :message_ids, :string
26
+ has_n_of_attribute :messages, :message
26
27
  has_n_of_attribute :participants, :participant
27
28
  attribute :snippet, :string
28
29
  attribute :starred, :boolean
data/lib/nylas/types.rb CHANGED
@@ -144,5 +144,16 @@ module Nylas
144
144
  end
145
145
  end
146
146
  Types.registry[:boolean] = BooleanType.new
147
+
148
+ # Type for attributes represented as floats.
149
+ class FloatType < ValueType
150
+ # @param value [Object] Strictly casts the passed in value to a boolean (must be true, not "" or 1)
151
+ def cast(value)
152
+ return nil if value.nil?
153
+
154
+ value.to_f
155
+ end
156
+ end
157
+ Types.registry[:float] = FloatType.new
147
158
  end
148
159
  end
data/lib/nylas/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nylas
4
- VERSION = "5.0.0"
4
+ VERSION = "5.4.0"
5
5
  end
data/lib/nylas/when.rb CHANGED
@@ -8,7 +8,7 @@ module Nylas
8
8
 
9
9
  include Model::Attributable
10
10
 
11
- attribute :object, :string
11
+ attribute :object, :string, read_only: true
12
12
 
13
13
  # when object == 'date'
14
14
  attribute :date, :date
data/lib/nylas.rb CHANGED
@@ -53,6 +53,9 @@ require_relative "nylas/nylas_date"
53
53
  require_relative "nylas/when"
54
54
  require_relative "nylas/free_busy"
55
55
  require_relative "nylas/time_slot"
56
+ require_relative "nylas/event_conferencing"
57
+ require_relative "nylas/event_conferencing_details"
58
+ require_relative "nylas/event_conferencing_autocreate"
56
59
 
57
60
  # Custom collection types
58
61
  require_relative "nylas/search_collection"
@@ -69,11 +72,25 @@ require_relative "nylas/deltas"
69
72
  require_relative "nylas/delta"
70
73
  require_relative "nylas/draft"
71
74
  require_relative "nylas/message"
75
+ require_relative "nylas/room_resource"
72
76
  require_relative "nylas/new_message"
73
77
  require_relative "nylas/raw_message"
74
78
  require_relative "nylas/thread"
75
79
  require_relative "nylas/webhook"
76
80
 
81
+ # Neural specific types
82
+ require_relative "nylas/neural"
83
+ require_relative "nylas/neural_sentiment_analysis"
84
+ require_relative "nylas/neural_ocr"
85
+ require_relative "nylas/neural_categorizer"
86
+ require_relative "nylas/neural_clean_conversation"
87
+ require_relative "nylas/neural_contact_link"
88
+ require_relative "nylas/neural_contact_name"
89
+ require_relative "nylas/neural_signature_contact"
90
+ require_relative "nylas/neural_signature_extraction"
91
+ require_relative "nylas/neural_message_options"
92
+ require_relative "nylas/categorize"
93
+
77
94
  require_relative "nylas/native_authentication"
78
95
 
79
96
  require_relative "nylas/http_client"
@@ -94,6 +111,7 @@ module Nylas
94
111
  Types.registry[:folder] = Types::ModelType.new(model: Folder)
95
112
  Types.registry[:im_address] = Types::ModelType.new(model: IMAddress)
96
113
  Types.registry[:label] = Types::ModelType.new(model: Label)
114
+ Types.registry[:room_resource] = Types::ModelType.new(model: RoomResource)
97
115
  Types.registry[:message] = Types::ModelType.new(model: Message)
98
116
  Types.registry[:message_headers] = MessageHeadersType.new
99
117
  Types.registry[:message_tracking] = Types::ModelType.new(model: MessageTracking)
@@ -108,4 +126,12 @@ module Nylas
108
126
  Types.registry[:contact_group] = Types::ModelType.new(model: ContactGroup)
109
127
  Types.registry[:when] = Types::ModelType.new(model: When)
110
128
  Types.registry[:time_slot] = Types::ModelType.new(model: TimeSlot)
129
+ Types.registry[:event_conferencing] = Types::ModelType.new(model: EventConferencing)
130
+ Types.registry[:event_conferencing_details] = Types::ModelType.new(model: EventConferencingDetails)
131
+ Types.registry[:event_conferencing_autocreate] = Types::ModelType.new(model: EventConferencingAutocreate)
132
+ Types.registry[:neural] = Types::ModelType.new(model: Neural)
133
+ Types.registry[:categorize] = Types::ModelType.new(model: Categorize)
134
+ Types.registry[:neural_signature_contact] = Types::ModelType.new(model: NeuralSignatureContact)
135
+ Types.registry[:neural_contact_link] = Types::ModelType.new(model: NeuralContactLink)
136
+ Types.registry[:neural_contact_name] = Types::ModelType.new(model: NeuralContactName)
111
137
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nylas
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0
4
+ version: 5.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nylas, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-07 00:00:00.000000000 Z
11
+ date: 2021-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -270,6 +270,7 @@ files:
270
270
  - lib/nylas/account.rb
271
271
  - lib/nylas/api.rb
272
272
  - lib/nylas/calendar.rb
273
+ - lib/nylas/categorize.rb
273
274
  - lib/nylas/collection.rb
274
275
  - lib/nylas/constraints.rb
275
276
  - lib/nylas/contact.rb
@@ -283,6 +284,9 @@ files:
283
284
  - lib/nylas/errors.rb
284
285
  - lib/nylas/event.rb
285
286
  - lib/nylas/event_collection.rb
287
+ - lib/nylas/event_conferencing.rb
288
+ - lib/nylas/event_conferencing_autocreate.rb
289
+ - lib/nylas/event_conferencing_details.rb
286
290
  - lib/nylas/file.rb
287
291
  - lib/nylas/filter_attributes.rb
288
292
  - lib/nylas/folder.rb
@@ -302,6 +306,16 @@ files:
302
306
  - lib/nylas/model/list_attribute_definition.rb
303
307
  - lib/nylas/model/transferable.rb
304
308
  - lib/nylas/native_authentication.rb
309
+ - lib/nylas/neural.rb
310
+ - lib/nylas/neural_categorizer.rb
311
+ - lib/nylas/neural_clean_conversation.rb
312
+ - lib/nylas/neural_contact_link.rb
313
+ - lib/nylas/neural_contact_name.rb
314
+ - lib/nylas/neural_message_options.rb
315
+ - lib/nylas/neural_ocr.rb
316
+ - lib/nylas/neural_sentiment_analysis.rb
317
+ - lib/nylas/neural_signature_contact.rb
318
+ - lib/nylas/neural_signature_extraction.rb
305
319
  - lib/nylas/new_message.rb
306
320
  - lib/nylas/nylas_date.rb
307
321
  - lib/nylas/participant.rb
@@ -310,6 +324,7 @@ files:
310
324
  - lib/nylas/raw_message.rb
311
325
  - lib/nylas/recurrence.rb
312
326
  - lib/nylas/registry.rb
327
+ - lib/nylas/room_resource.rb
313
328
  - lib/nylas/rsvp.rb
314
329
  - lib/nylas/search_collection.rb
315
330
  - lib/nylas/thread.rb
@@ -345,7 +360,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
345
360
  - !ruby/object:Gem::Version
346
361
  version: '0'
347
362
  requirements: []
348
- rubygems_version: 3.1.2
363
+ rubygems_version: 3.2.17
349
364
  signing_key:
350
365
  specification_version: 4
351
366
  summary: Gem for interacting with the Nylas API