nylas 5.4.1 → 5.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29f07de83f9f9129d2604b28ad5efd02d21cdc81075e92b16129d6ebfb3509fc
4
- data.tar.gz: f1259c4907de58f04082c6c2e0a80a7d2d50b99a13efc70714f7370ead25d420
3
+ metadata.gz: 4d8d9639941076724b3e9ae95b85a2e4a48c8f663a35b03f5f26473c5c87b208
4
+ data.tar.gz: 4b2733e86538a6dd7ac3069dc5738997ea8db1b7be13b1a8de9bef5c868ec1d5
5
5
  SHA512:
6
- metadata.gz: 9117a61ff796ee58ee596d2ce7f1d41874a0f79f452d678f66dc768e8cf7db59580085f069946e4d4a634b47a85ebd4696f59b59960ecdec805c0244575bbc7a
7
- data.tar.gz: b53cedb0c8c2334da1f6e092819eea787ec4c856eafdb606ce29713605eed834044e780dfd6ed6fafc0ee47c6c1bfd48d947237dc4dd9a6d84d531c4c5cc1daf
6
+ metadata.gz: 56b9216d9e5f37a0c449d999891a76a06e1ed8dd8925efe5186d8d59d16105da76ea3b8a5599d88a9e8e83bd2862bc71cc7491957ac8c8da8718a825af2a2a2a
7
+ data.tar.gz: 5fa04ae09e9692f0c954926ae8e7d541388597a12a154dd8bf82b78c40e91b7b9b73508c5d39b6a2c604ed5d53f5eec86379687dc9b79da81b4a8571d0500460
data/lib/nylas/account.rb CHANGED
@@ -7,15 +7,18 @@ module Nylas
7
7
  include Model
8
8
  self.listable = true
9
9
  self.showable = true
10
+ self.updatable = true
11
+ self.destroyable = true
10
12
 
11
- attribute :id, :string
12
- attribute :account_id, :string
13
- attribute :billing_state, :string
14
- attribute :sync_state, :string
15
- attribute :provider, :string
13
+ attribute :id, :string, read_only: true
14
+ attribute :account_id, :string, read_only: true
15
+ attribute :billing_state, :string, read_only: true
16
+ attribute :sync_state, :string, read_only: true
17
+ attribute :provider, :string, read_only: true
16
18
 
17
- attribute :email, :string
18
- attribute :trial, :boolean
19
+ attribute :email, :string, read_only: true
20
+ attribute :trial, :boolean, read_only: true
21
+ attribute :metadata, :hash
19
22
 
20
23
  def upgrade
21
24
  response = execute(method: :post, path: "#{resource_path}/upgrade")
@@ -34,6 +37,15 @@ module Nylas
34
37
  response[:success]
35
38
  end
36
39
 
40
+ # Return information about an account's access token
41
+ # @param access_token [String] The access token to inquire about
42
+ # @return [TokenInfo] The access token information
43
+ def token_info(access_token)
44
+ payload = JSON.dump(access_token: access_token)
45
+ response = execute(method: :post, path: "#{resource_path}/token-info", payload: payload)
46
+ TokenInfo.new(**response)
47
+ end
48
+
37
49
  def self.resources_path(api:)
38
50
  "/a/#{api.app_id}/accounts"
39
51
  end
data/lib/nylas/api.rb CHANGED
@@ -48,7 +48,11 @@ module Nylas
48
48
  "#{api_server}/oauth/authorize?#{URI.encode_www_form(params)}"
49
49
  end
50
50
 
51
- def exchange_code_for_token(code)
51
+ # Exchanges an authorization code for an access token
52
+ # @param code [String] The authorization code to exchange
53
+ # @param return_full_response [Boolean] If true, returns the full response body instead of just the token
54
+ # @return [String | Hash] Returns just the access token as a string, or the full response as a hash
55
+ def exchange_code_for_token(code, return_full_response: false)
52
56
  data = {
53
57
  "client_id" => app_id,
54
58
  "client_secret" => client.app_secret,
@@ -56,8 +60,8 @@ module Nylas
56
60
  "code" => code
57
61
  }
58
62
 
59
- response_json = execute(method: :post, path: "/oauth/token", payload: data)
60
- response_json[:access_token]
63
+ response = execute(method: :post, path: "/oauth/token", payload: data)
64
+ return_full_response ? response : response[:access_token]
61
65
  end
62
66
 
63
67
  # @return [Collection<Contact>] A queryable collection of Contacts
@@ -81,9 +85,9 @@ module Nylas
81
85
  @accounts ||= Collection.new(model: Account, api: as(client.app_secret))
82
86
  end
83
87
 
84
- # @return [Collection<Calendar>] A queryable collection of {Calendar}s
88
+ # @return [CalendarCollection<Calendar>] A queryable collection of {Calendar}s
85
89
  def calendars
86
- @calendars ||= Collection.new(model: Calendar, api: self)
90
+ @calendars ||= CalendarCollection.new(model: Calendar, api: self)
87
91
  end
88
92
 
89
93
  # @return [DeltasCollection<Delta>] A queryable collection of Deltas, which are themselves a collection.
@@ -96,7 +100,7 @@ module Nylas
96
100
  @drafts ||= Collection.new(model: Draft, api: self)
97
101
  end
98
102
 
99
- # @return [Collection<Event>] A queryable collection of {Event}s
103
+ # @return [EventCollection<Event>] A queryable collection of {Event}s
100
104
  def events
101
105
  @events ||= EventCollection.new(model: Event, api: self)
102
106
  end
@@ -126,11 +130,29 @@ module Nylas
126
130
  @room_resources ||= Collection.new(model: RoomResource, api: self)
127
131
  end
128
132
 
133
+ # @return[Collection<JobStatus>] A queryable collection of {JobStatus} objects
134
+ def job_statuses
135
+ @job_statuses ||= Collection.new(model: JobStatus, api: self)
136
+ end
137
+
138
+ # @return[SchedulerCollection<Scheduler>] A queryable collection of {Scheduler} objects
139
+ def scheduler
140
+ # Make a deep copy of the API as the scheduler API uses a different base URL
141
+ scheduler_api = Marshal.load(Marshal.dump(self))
142
+ scheduler_api.client.api_server = "https://api.schedule.nylas.com"
143
+ @scheduler ||= SchedulerCollection.new(model: Scheduler, api: scheduler_api)
144
+ end
145
+
129
146
  # @return[Neural] A {Neural} object that provides
130
147
  def neural
131
148
  @neural ||= Neural.new(api: self)
132
149
  end
133
150
 
151
+ # @return [Collection<Component>] A queryable collection of {Component}s
152
+ def components
153
+ @components ||= ComponentCollection.new(model: Component, api: as(client.app_secret))
154
+ end
155
+
134
156
  # Revokes access to the Nylas API for the given access token
135
157
  # @return [Boolean]
136
158
  def revoke(access_token)
@@ -138,6 +160,25 @@ module Nylas
138
160
  response.code == 200 && response.empty?
139
161
  end
140
162
 
163
+ # Returns the application details
164
+ # @return [ApplicationDetail] The application details
165
+ def application_details
166
+ response = client.as(client.app_secret).execute(method: :get, path: "/a/#{app_id}")
167
+ ApplicationDetail.new(**response)
168
+ end
169
+
170
+ # Updates the application details
171
+ # @param application_details [ApplicationDetail] The updated application details
172
+ # @return [ApplicationDetails] The updated application details, returned from the server
173
+ def update_application_details(application_details)
174
+ response = client.as(client.app_secret).execute(
175
+ method: :put,
176
+ path: "/a/#{app_id}",
177
+ payload: JSON.dump(application_details.to_h)
178
+ )
179
+ ApplicationDetail.new(**response)
180
+ end
181
+
141
182
  # Returns list of IP addresses
142
183
  # @return [Hash]
143
184
  # hash has keys of :updated_at (unix timestamp) and :ip_addresses (array of strings)
@@ -155,7 +196,7 @@ module Nylas
155
196
  end
156
197
 
157
198
  # Allows you to get an API that acts as a different user but otherwise has the same settings
158
- # @param [String] Oauth Access token or app secret used to authenticate with the API
199
+ # @param access_token [String] Oauth Access token or app secret used to authenticate with the API
159
200
  # @return [API]
160
201
  def as(access_token)
161
202
  API.new(client: client.as(access_token))
@@ -171,6 +212,7 @@ module Nylas
171
212
  @webhooks ||= Collection.new(model: Webhook, api: as(client.app_secret))
172
213
  end
173
214
 
215
+ # TODO: Move this into calendar collection
174
216
  def free_busy(emails:, start_time:, end_time:)
175
217
  FreeBusyCollection.new(
176
218
  api: self,
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a Nylas Application Detail object.
5
+ # @see https://developer.nylas.com/docs/api/#get/a/client_id
6
+ class ApplicationDetail
7
+ include Model::Attributable
8
+
9
+ attribute :application_name, :string
10
+ attribute :icon_url, :string
11
+ has_n_of_attribute :redirect_uris, :string
12
+ end
13
+ end
@@ -6,7 +6,8 @@ module Nylas
6
6
  class Calendar
7
7
  include Model
8
8
  self.resources_path = "/calendars"
9
- allows_operations(listable: true, filterable: true, showable: true)
9
+ allows_operations(creatable: true, listable: true, filterable: true, showable: true, updatable: true,
10
+ destroyable: true)
10
11
 
11
12
  attribute :id, :string
12
13
  attribute :account_id, :string
@@ -20,6 +21,8 @@ module Nylas
20
21
  attribute :timezone, :string
21
22
 
22
23
  attribute :read_only, :boolean
24
+ attribute :metadata, :hash
25
+ attribute :job_status_id, :string, read_only: true
23
26
 
24
27
  def read_only?
25
28
  read_only == true
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Additional methods for some of Calendar's other functionality
5
+ # @see https://developer.nylas.com/docs/connectivity/calendar
6
+ class CalendarCollection < Collection
7
+ def availability(duration_minutes:,
8
+ interval:,
9
+ start_time:,
10
+ end_time:,
11
+ emails:,
12
+ buffer: nil,
13
+ round_robin: nil,
14
+ free_busy: [],
15
+ open_hours: [])
16
+ validate_open_hours(emails, free_busy, open_hours) unless open_hours.empty?
17
+
18
+ execute_availability("/calendars/availability",
19
+ duration_minutes: duration_minutes,
20
+ interval: interval,
21
+ start_time: start_time,
22
+ end_time: end_time,
23
+ emails: emails,
24
+ buffer: buffer,
25
+ round_robin: round_robin,
26
+ free_busy: free_busy,
27
+ open_hours: open_hours)
28
+ end
29
+
30
+ def consecutive_availability(duration_minutes:,
31
+ interval:,
32
+ start_time:,
33
+ end_time:,
34
+ emails:,
35
+ buffer: nil,
36
+ free_busy: [],
37
+ open_hours: [])
38
+ validate_open_hours(emails, free_busy, open_hours) unless open_hours.empty?
39
+
40
+ execute_availability("/calendars/availability/consecutive",
41
+ duration_minutes: duration_minutes,
42
+ interval: interval,
43
+ start_time: start_time,
44
+ end_time: end_time,
45
+ emails: emails,
46
+ buffer: buffer,
47
+ free_busy: free_busy,
48
+ open_hours: open_hours)
49
+ end
50
+
51
+ private
52
+
53
+ def execute_availability(path, **payload)
54
+ api.execute(
55
+ method: :post,
56
+ path: path,
57
+ payload: JSON.dump(payload)
58
+ )
59
+ end
60
+
61
+ def validate_open_hours(emails, free_busy, open_hours)
62
+ raise TypeError, "open_hours' must be an array." unless open_hours.is_a?(Array)
63
+
64
+ open_hours_emails = map_open_hours_emails(open_hours)
65
+ free_busy_emails = map_free_busy_emails(free_busy)
66
+ emails = merge_arrays(emails) if emails[0].is_a?(Array)
67
+
68
+ open_hours_emails.each do |email|
69
+ next if emails.include?(email) || free_busy_emails.include?(email)
70
+
71
+ raise ArgumentError, "Open Hours cannot contain an email not present in the main email list or
72
+ the free busy email list."
73
+ end
74
+ end
75
+
76
+ def map_open_hours_emails(open_hours)
77
+ open_hours_emails = []
78
+ open_hours.map do |oh|
79
+ open_hours_emails += oh.emails
80
+ end
81
+ open_hours_emails
82
+ end
83
+
84
+ def map_free_busy_emails(free_busy)
85
+ free_busy_emails = []
86
+ free_busy.map do |fb|
87
+ free_busy_emails.append(fb.email)
88
+ end
89
+ free_busy_emails
90
+ end
91
+
92
+ def merge_arrays(array)
93
+ list = []
94
+ array.each do |x|
95
+ list += x
96
+ end
97
+ list
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent a the Component Schema.
5
+ class Component
6
+ include Model
7
+ allows_operations(creatable: true, listable: true, filterable: true, showable: true, updatable: true,
8
+ destroyable: true)
9
+
10
+ attribute :id, :string, read_only: true
11
+ attribute :account_id, :string
12
+ attribute :name, :string
13
+ attribute :type, :string
14
+ attribute :action, :integer
15
+ attribute :active, :boolean
16
+ attribute :settings, :hash
17
+ attribute :public_account_id, :string
18
+ attribute :public_token_id, :string
19
+ attribute :public_application_id, :string, read_only: true
20
+ attribute :access_token, :string
21
+ attribute :created_at, :date, read_only: true
22
+ attribute :updated_at, :date, read_only: true
23
+
24
+ has_n_of_attribute :allowed_domains, :string
25
+
26
+ def resources_path(*)
27
+ "/component/#{api.client.app_id}"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Additional configuration for the Component CRUD API
5
+ class ComponentCollection < Collection
6
+ def resources_path
7
+ "/component/#{api.client.app_id}"
8
+ end
9
+ end
10
+ end
data/lib/nylas/contact.rb CHANGED
@@ -30,6 +30,7 @@ module Nylas
30
30
  attribute :office_location, :string
31
31
  attribute :notes, :string
32
32
  attribute :source, :string
33
+ attribute :job_status_id, :string, read_only: true
33
34
 
34
35
  has_n_of_attribute :groups, :contact_group
35
36
  has_n_of_attribute :emails, :email_address
data/lib/nylas/draft.rb CHANGED
@@ -27,6 +27,7 @@ module Nylas
27
27
  attribute :body, :string
28
28
  attribute :starred, :boolean
29
29
  attribute :unread, :boolean
30
+ attribute :metadata, :hash
30
31
 
31
32
  has_n_of_attribute :events, :event
32
33
  has_n_of_attribute :files, :file, read_only: true
@@ -35,6 +36,7 @@ module Nylas
35
36
  has_n_of_attribute :labels, :label
36
37
 
37
38
  attribute :tracking, :message_tracking
39
+ attribute :job_status_id, :string, read_only: true
38
40
 
39
41
  transfer :api, to: %i[events files folder labels]
40
42
 
@@ -75,18 +77,18 @@ module Nylas
75
77
  execute(method: :delete, path: resource_path, payload: attributes.serialize_for_api(keys: [:version]))
76
78
  end
77
79
 
78
- private
79
-
80
- def save_call
80
+ def save
81
81
  extract_file_ids!
82
82
 
83
83
  super
84
84
  end
85
85
 
86
+ private
87
+
86
88
  def extract_file_ids!
87
89
  files = self.files || []
88
90
 
89
- self.file_ids = files.map(&:id)
91
+ self.file_ids ||= files.map(&:id)
90
92
  end
91
93
  end
92
94
  end
data/lib/nylas/event.rb CHANGED
@@ -29,7 +29,9 @@ module Nylas
29
29
  attribute :when, :when
30
30
  attribute :metadata, :hash
31
31
  attribute :conferencing, :event_conferencing
32
+ has_n_of_attribute :notifications, :event_notification
32
33
  attribute :original_start_time, :unix_timestamp
34
+ attribute :job_status_id, :string, read_only: true
33
35
 
34
36
  attr_accessor :notify_participants
35
37
 
@@ -58,8 +60,47 @@ module Nylas
58
60
  rsvp.save
59
61
  end
60
62
 
63
+ # Generate an ICS file server-side, from an Event
64
+ # @param ical_uid [String] Unique identifier used events across calendaring systems
65
+ # @param method [String] Description of invitation and response methods for attendees
66
+ # @param prodid [String] Company-specific unique product identifier
67
+ # @return [String] String for writing directly into an ICS file
68
+ def generate_ics(ical_uid: nil, method: nil, prodid: nil)
69
+ raise ArgumentError, "Cannot generate an ICS file for an event without a Calendar ID or when set" unless
70
+ calendar_id && self.when
71
+
72
+ payload = build_ics_event_payload(ical_uid, method, prodid)
73
+ response = api.execute(
74
+ method: :post,
75
+ path: "#{resources_path}/to-ics",
76
+ payload: JSON.dump(payload)
77
+ )
78
+
79
+ response[:ics]
80
+ end
81
+
61
82
  private
62
83
 
84
+ def build_ics_event_payload(ical_uid, method, prodid)
85
+ payload = {}
86
+ if id
87
+ payload[:event_id] = id
88
+ else
89
+ payload = to_h(enforce_read_only: true)
90
+ end
91
+ ics_options = build_ics_options_payload(ical_uid, method, prodid)
92
+ payload["ics_options"] = ics_options unless ics_options.empty?
93
+ payload
94
+ end
95
+
96
+ def build_ics_options_payload(ical_uid, method, prodid)
97
+ payload = {}
98
+ payload["ical_uid"] = ical_uid if ical_uid
99
+ payload["method"] = method if method
100
+ payload["prodid"] = prodid if prodid
101
+ payload
102
+ end
103
+
63
104
  def query_params
64
105
  if notify_participants.nil?
65
106
  {}
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the Event Notification object
5
+ # @see https://developer.nylas.com/docs/connectivity/calendar/event-notifications
6
+ class EventNotification
7
+ include Model::Attributable
8
+
9
+ attribute :type, :string
10
+ attribute :minutes_before_event, :integer
11
+ attribute :url, :string
12
+ attribute :payload, :string
13
+ attribute :subject, :string
14
+ attribute :body, :string
15
+ attribute :message, :string
16
+ end
17
+ end
data/lib/nylas/file.rb CHANGED
@@ -6,7 +6,7 @@ module Nylas
6
6
  class File
7
7
  include Model
8
8
  self.resources_path = "/files"
9
- allows_operations(listable: true, showable: true, filterable: true, creatable: true)
9
+ allows_operations(listable: true, showable: true, filterable: true, creatable: true, destroyable: true)
10
10
 
11
11
  attribute :id, :string
12
12
  attribute :account_id, :string
data/lib/nylas/folder.rb CHANGED
@@ -13,12 +13,12 @@ module Nylas
13
13
  self.updatable = true
14
14
  self.destroyable = true
15
15
 
16
- attribute :id, :string
17
- attribute :account_id, :string
18
-
19
- attribute :object, :string
16
+ attribute :id, :string, read_only: true
17
+ attribute :account_id, :string, read_only: true
18
+ attribute :object, :string, read_only: true
20
19
 
21
20
  attribute :name, :string
22
21
  attribute :display_name, :string
22
+ attribute :job_status_id, :string, read_only: true
23
23
  end
24
24
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
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
+ allows_operations(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 :original_data, :message, read_only: true
19
+
20
+ # Returns the status of a job as a boolean
21
+ # @return [Boolean] If the job was successful
22
+ def successful?
23
+ status == "successful"
24
+ end
25
+ end
26
+ end
data/lib/nylas/label.rb CHANGED
@@ -20,5 +20,6 @@ module Nylas
20
20
 
21
21
  attribute :name, :string
22
22
  attribute :display_name, :string
23
+ attribute :job_status_id, :string, read_only: true
23
24
  end
24
25
  end
data/lib/nylas/message.rb CHANGED
@@ -8,7 +8,7 @@ module Nylas
8
8
  self.raw_mime_type = "message/rfc822"
9
9
  self.resources_path = "/messages"
10
10
  allows_operations(showable: true, listable: true, filterable: true, searchable: true, updatable: true)
11
- UPDATABLE_ATTRIBUTES = %i[label_ids folder_id starred unread].freeze
11
+ UPDATABLE_ATTRIBUTES = %i[label_ids folder_id starred unread metadata].freeze
12
12
 
13
13
  attribute :id, :string
14
14
  attribute :object, :string
@@ -36,6 +36,8 @@ module Nylas
36
36
  has_n_of_attribute :files, :file
37
37
  attribute :folder, :folder
38
38
  attribute :folder_id, :string
39
+ attribute :metadata, :hash
40
+ attribute :job_status_id, :string, read_only: true
39
41
 
40
42
  has_n_of_attribute :labels, :label, read_only: true
41
43
  has_n_of_attribute :label_ids, :string
@@ -72,14 +74,10 @@ module Nylas
72
74
  self
73
75
  end
74
76
 
75
- def save_call
77
+ def save
76
78
  handle_folder
77
79
 
78
- execute(
79
- method: :put,
80
- payload: attributes.serialize_for_api,
81
- path: resource_path
82
- )
80
+ super
83
81
  end
84
82
 
85
83
  def handle_folder
@@ -17,8 +17,8 @@ module Nylas
17
17
  end
18
18
 
19
19
  # @return [Hash] Representation of the model with values serialized into primitives based on their Type
20
- def to_h
21
- attributes.to_h
20
+ def to_h(enforce_read_only: false)
21
+ attributes.to_h(enforce_read_only: enforce_read_only)
22
22
  end
23
23
 
24
24
  protected
@@ -5,7 +5,7 @@ module Nylas
5
5
  # Define a particular attribute for a given model
6
6
  class AttributeDefinition
7
7
  extend Forwardable
8
- def_delegators :type, :cast, :serialize
8
+ def_delegators :type, :cast, :serialize, :serialize_for_api
9
9
  attr_accessor :type_name, :read_only, :default
10
10
 
11
11
  def initialize(type_name:, read_only:, default:)
@@ -28,23 +28,34 @@ module Nylas
28
28
  end
29
29
  end
30
30
 
31
- def to_h(keys: attribute_definitions.keys)
32
- keys.each_with_object({}) do |key, casted_data|
33
- value = attribute_definitions[key].serialize(self[key])
31
+ # Convert the object to hash
32
+ # @param keys [Array<String>] The keys included
33
+ # @param enforce_read_only [Boolean] Whether to enforce read_only property (serializing for API)
34
+ # @return [Hash] The hash representation of the object
35
+ def to_h(keys: attribute_definitions.keys, enforce_read_only: false)
36
+ casted_data = {}
37
+ keys.each do |key|
38
+ value = attribute_to_hash(key, enforce_read_only)
34
39
  # If the value is an empty hash but we specify that it is valid (via default value), serialize it
35
40
  casted_data[key] = value unless value.nil? || (value.respond_to?(:empty?) && value.empty? &&
36
41
  !(attribute_definitions[key].default == value && value.is_a?(Hash)))
37
42
  end
43
+ casted_data
38
44
  end
39
45
 
40
- def serialize(keys: attribute_definitions.keys)
41
- JSON.dump(to_h(keys: keys))
46
+ # Serialize the object
47
+ # @param keys [Array<String>] The keys included
48
+ # @param enforce_read_only [Boolean] Whether to enforce read_only property (serializing for API)
49
+ # @return [String] The serialized object as a JSON string
50
+ def serialize(keys: attribute_definitions.keys, enforce_read_only: false)
51
+ JSON.dump(to_h(keys: keys, enforce_read_only: enforce_read_only))
42
52
  end
43
53
 
54
+ # Serialize the object to an API-compatible JSON string
55
+ # @param keys [Array<String>] The keys included
56
+ # @return [String] The serialized object as a JSON string
44
57
  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)
58
+ serialize(keys: keys, enforce_read_only: true)
48
59
  end
49
60
 
50
61
  def serialize_all_for_api(keys: attribute_definitions.keys)
@@ -68,6 +79,19 @@ module Nylas
68
79
  def default_attributes
69
80
  attribute_definitions.keys.zip([]).to_h
70
81
  end
82
+
83
+ # Convert the attribute value as a hash
84
+ # @param key [String] The attribute's key
85
+ # @param enforce_read_only [Boolean] Whether to enforce read_only property (serializing for API)
86
+ # @return [nil | Hash] The appropriately serialized value
87
+ def attribute_to_hash(key, enforce_read_only)
88
+ attribute_definition = attribute_definitions[key]
89
+ if enforce_read_only
90
+ attribute_definition.read_only == true ? nil : attribute_definition.serialize_for_api(self[key])
91
+ else
92
+ attribute_definition.serialize(self[key])
93
+ end
94
+ end
71
95
  end
72
96
  end
73
97
  end
@@ -18,9 +18,17 @@ module Nylas
18
18
  list.map { |item| type.cast(item) }
19
19
  end
20
20
 
21
- def serialize(list)
21
+ def serialize(list, enforce_read_only: false)
22
22
  list = default if list.nil? || list.empty?
23
- list.map { |item| type.serialize(item) }
23
+ if enforce_read_only
24
+ list.map { |item| type.serialize_for_api(item) }
25
+ else
26
+ list.map { |item| type.serialize(item) }
27
+ end
28
+ end
29
+
30
+ def serialize_for_api(list)
31
+ serialize(list, enforce_read_only: true)
24
32
  end
25
33
 
26
34
  def type
data/lib/nylas/model.rb CHANGED
@@ -28,7 +28,7 @@ module Nylas
28
28
  result = if persisted?
29
29
  raise ModelNotUpdatableError, self unless updatable?
30
30
 
31
- save_call
31
+ update_call(attributes.serialize_for_api)
32
32
  else
33
33
  create
34
34
  end
@@ -120,14 +120,6 @@ module Nylas
120
120
 
121
121
  private
122
122
 
123
- def save_call
124
- execute(
125
- method: :put,
126
- payload: attributes.serialize_for_api,
127
- path: resource_path
128
- )
129
- end
130
-
131
123
  def update_call(payload)
132
124
  result = execute(
133
125
  method: :put,
@@ -20,6 +20,7 @@ module Nylas
20
20
  attribute :subject, :string
21
21
  attribute :body, :string
22
22
  attribute :reply_to_message_id, :string
23
+ attribute :metadata, :hash
23
24
 
24
25
  has_n_of_attribute :file_ids, :string
25
26
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Additional times email accounts are available
5
+ # @see https://developer.nylas.com/docs/api/#post/calendars/availability
6
+ class OpenHours
7
+ include Model::Attributable
8
+
9
+ attribute :timezone, :string
10
+ attribute :start, :string
11
+ attribute :end, :string
12
+ has_n_of_attribute :emails, :string
13
+ has_n_of_attribute :days, :integer
14
+ end
15
+ end
@@ -7,6 +7,6 @@ module Nylas
7
7
  attribute :name, :string
8
8
  attribute :email, :string
9
9
  attribute :comment, :string
10
- attribute :status, :string
10
+ attribute :status, :string, read_only: true
11
11
  end
12
12
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Ruby representation of a the Nylas Scheduler API
5
+ # @see https://developer.nylas.com/docs/api/scheduler/#overview
6
+ class Scheduler
7
+ include Model
8
+ self.resources_path = "/manage/pages"
9
+ allows_operations(creatable: true, listable: true, filterable: true, showable: true, updatable: true,
10
+ destroyable: true)
11
+
12
+ attribute :id, :integer, read_only: true
13
+ attribute :app_client_id, :string
14
+ attribute :app_organization_id, :integer
15
+ attribute :config, :scheduler_config
16
+ attribute :edit_token, :string
17
+ attribute :name, :string
18
+ attribute :slug, :string
19
+ attribute :created_at, :date
20
+ attribute :modified_at, :date
21
+
22
+ has_n_of_attribute :access_tokens, :string
23
+
24
+ def get_available_calendars
25
+ raise ArgumentError, "Cannot get calendars for a page without an ID." if id.nil?
26
+
27
+ api.execute(
28
+ method: :get,
29
+ path: "/manage/pages/#{id}/calendars"
30
+ )
31
+ end
32
+
33
+ def upload_image(content_type:, object_name:)
34
+ raise ArgumentError, "Cannot upload an image to a page without an ID." if id.nil?
35
+
36
+ payload = {
37
+ contentType: content_type,
38
+ objectName: object_name
39
+ }
40
+ api.execute(
41
+ method: :put,
42
+ path: "/manage/pages/#{id}/upload-image",
43
+ payload: JSON.dump(payload)
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the booking response returned from the Scheduler API
5
+ class SchedulerBookingConfirmation
6
+ include Model::Attributable
7
+ attribute :id, :integer
8
+ attribute :account_id, :string
9
+ attribute :calendar_event_id, :string
10
+ attribute :calendar_id, :string
11
+ attribute :edit_hash, :string
12
+ attribute :location, :string
13
+ attribute :title, :string
14
+ attribute :recipient_email, :string
15
+ attribute :recipient_locale, :string
16
+ attribute :recipient_name, :string
17
+ attribute :recipient_tz, :string
18
+ attribute :additional_field_values, :hash
19
+ attribute :is_confirmed, :boolean
20
+ attribute :start_time, :unix_timestamp
21
+ attribute :end_time, :unix_timestamp
22
+ has_n_of_attribute :additional_emails, :string
23
+ end
24
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the booking request used for the Scheduler API
5
+ class SchedulerBookingRequest
6
+ include Model::Attributable
7
+ attribute :additional_values, :hash
8
+ attribute :email, :string
9
+ attribute :locale, :string
10
+ attribute :name, :string
11
+ attribute :page_hostname, :string
12
+ attribute :replaces_booking_hash, :string
13
+ attribute :timezone, :string
14
+ attribute :slot, :scheduler_time_slot
15
+ has_n_of_attribute :additional_emails, :string
16
+ end
17
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Additional methods for some of Scheduler's other functionality
5
+ # @see https://developer.nylas.com/docs/api/scheduler#overview
6
+ class SchedulerCollection < Collection
7
+ # Retrieve Google availability
8
+ # @return [Hash] Returns the availability
9
+ def get_google_availability
10
+ execute_provider_availability("google")
11
+ end
12
+
13
+ # Retrieve Office 365 availability
14
+ # @return [Hash] Returns the availability
15
+ def get_office_365_availability
16
+ execute_provider_availability("o365")
17
+ end
18
+
19
+ # Retrieve public config for a scheduling page
20
+ # @param slug [String] The Scheduler page slug
21
+ # @return [Scheduler] Returns the Scheduler object representing the page configuration
22
+ def get_page_slug(slug)
23
+ page_response = api.execute(
24
+ method: :get,
25
+ path: "/schedule/#{slug}/info"
26
+ )
27
+
28
+ Scheduler.new(**page_response.merge(api: api))
29
+ end
30
+
31
+ # Retrieve available time slots
32
+ # @param slug [String] The Scheduler page slug
33
+ # @return [Array<SchedulerTimeSlot>] Returns the list of available timeslots
34
+ def get_available_time_slots(slug)
35
+ response = api.execute(
36
+ method: :get,
37
+ path: "/schedule/#{slug}/timeslots"
38
+ )
39
+
40
+ timeslots = []
41
+ response.each do |available_slot|
42
+ timeslots.push(SchedulerTimeSlot.new(**available_slot.merge(api: api)))
43
+ end
44
+ timeslots
45
+ end
46
+
47
+ # Book a time slot
48
+ # @param slug [String] The Scheduler page slug
49
+ # @param timeslot [SchedulerBookingRequest] The time slot booking request
50
+ # @return [SchedulerBookingConfirmation] Returns the booking confirmation
51
+ def book_time_slot(slug, timeslot)
52
+ payload = timeslot.to_h
53
+ # The booking endpoint requires additional_values and additional_emails
54
+ # to exist regardless if they are empty or not
55
+ payload[:additional_values] = {} unless payload[:additional_values]
56
+ payload[:additional_emails] = [] unless payload[:additional_emails]
57
+ booking_response = api.execute(
58
+ method: :post,
59
+ path: "/schedule/#{slug}/timeslots",
60
+ payload: JSON.dump(payload)
61
+ )
62
+
63
+ SchedulerBookingConfirmation.new(**booking_response.merge(api: api))
64
+ end
65
+
66
+ # Cancel a booking
67
+ # @param slug [String] The Scheduler page slug
68
+ # @param edit_hash [String] The token used for editing the booked time slot
69
+ # @param reason [String] The reason for cancelling the booking
70
+ # @return [Hash] Returns a hash of a boolean representing success of cancellation
71
+ def cancel_booking(slug, edit_hash, reason)
72
+ api.execute(
73
+ method: :post,
74
+ path: "/schedule/#{slug}/#{edit_hash}/cancel",
75
+ payload: JSON.dump(reason: reason)
76
+ )
77
+ end
78
+
79
+ # Confirm a booking
80
+ # @param slug [String] The Scheduler page slug
81
+ # @param edit_hash [String] The token used for editing the booked time slot
82
+ # @return [SchedulerBookingConfirmation] Returns the confirmed booking confirmation
83
+ def confirm_booking(slug, edit_hash)
84
+ booking_response = api.execute(
85
+ method: :post,
86
+ path: "/schedule/#{slug}/#{edit_hash}/confirm",
87
+ payload: {}
88
+ )
89
+
90
+ SchedulerBookingConfirmation.new(**booking_response.merge(api: api))
91
+ end
92
+
93
+ private
94
+
95
+ # Retrieve provider availability
96
+ # @return [Hash] Returns the availability
97
+ def execute_provider_availability(provider)
98
+ api.execute(
99
+ method: :get,
100
+ path: "/schedule/availability/#{provider}"
101
+ )
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Configuration settings for a Scheduler page
5
+ # @see https://developer.nylas.com/docs/api/scheduler
6
+ class SchedulerConfig
7
+ include Model::Attributable
8
+
9
+ attribute :appearance, :hash
10
+ attribute :booking, :hash
11
+ attribute :calendar_ids, :hash
12
+ attribute :event, :hash
13
+ attribute :expire_after, :hash
14
+ attribute :locale, :string
15
+ attribute :locale_for_guests, :string
16
+ attribute :timezone, :string
17
+
18
+ has_n_of_attribute :reminders, :hash
19
+ end
20
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent the time slot object from the Scheduler API
5
+ class SchedulerTimeSlot
6
+ include Model::Attributable
7
+ attribute :account_id, :string
8
+ attribute :calendar_id, :string
9
+ attribute :host_name, :string
10
+ attribute :start, :unix_timestamp
11
+ attribute :end, :unix_timestamp
12
+ has_n_of_attribute :emails, :string
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Nylas
4
+ # Structure to represent information about a Nylas access token.
5
+ # @see https://developer.nylas.com/docs/api/#post/a/client_id/accounts/id/token-info
6
+ class TokenInfo
7
+ include Model::Attributable
8
+
9
+ attribute :scopes, :string
10
+ attribute :state, :string
11
+ attribute :created_at, :unix_timestamp
12
+ attribute :updated_at, :unix_timestamp
13
+
14
+ # Returns the state of the token as a boolean
15
+ # @return [Boolean] If the token is active
16
+ def valid?
17
+ state == "valid"
18
+ end
19
+ end
20
+ end
data/lib/nylas/types.rb CHANGED
@@ -7,8 +7,27 @@ module Nylas
7
7
  @registry ||= Registry.new
8
8
  end
9
9
 
10
+ # Base type for attributes
11
+ class ValueType
12
+ def cast(object)
13
+ object
14
+ end
15
+
16
+ def serialize(object)
17
+ object
18
+ end
19
+
20
+ def deseralize(object)
21
+ object
22
+ end
23
+
24
+ def serialize_for_api(object)
25
+ serialize(object)
26
+ end
27
+ end
28
+
10
29
  # Casts/Serializes data that is persisted and used natively as a Hash
11
- class HashType
30
+ class HashType < ValueType
12
31
  def serialize(object)
13
32
  object.to_h
14
33
  end
@@ -22,10 +41,11 @@ module Nylas
22
41
 
23
42
  # Type for attributes that are persisted in the API as a hash but exposed in ruby as a particular
24
43
  # {Model} or Model-like thing.
25
- class ModelType
44
+ class ModelType < ValueType
26
45
  attr_accessor :model
27
46
 
28
47
  def initialize(model:)
48
+ super()
29
49
  self.model = model
30
50
  end
31
51
 
@@ -33,6 +53,10 @@ module Nylas
33
53
  object.to_h
34
54
  end
35
55
 
56
+ def serialize_for_api(object)
57
+ object&.to_h(enforce_read_only: true)
58
+ end
59
+
36
60
  def cast(value)
37
61
  return model.new if value.nil?
38
62
  return value if already_cast?(value)
@@ -56,23 +80,8 @@ module Nylas
56
80
  end
57
81
  end
58
82
 
59
- # Type for attributes that do not require casting/serializing/deserializing.
60
- class ValueType
61
- def cast(object)
62
- object
63
- end
64
-
65
- def serialize(object)
66
- object
67
- end
68
-
69
- def deseralize(object)
70
- object
71
- end
72
- end
73
-
74
83
  # Type for attributes represented as a unix timestamp in the API and Time in Ruby
75
- class UnixTimestampType
84
+ class UnixTimestampType < ValueType
76
85
  def cast(object)
77
86
  return object if object.is_a?(Time) || object.nil?
78
87
  return Time.at(object.to_i) if object.is_a?(String)
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.4.1"
4
+ VERSION = "5.7.0"
5
5
  end
data/lib/nylas.rb CHANGED
@@ -35,7 +35,6 @@ require_relative "nylas/model"
35
35
  # Attribute types supported by the API
36
36
  require_relative "nylas/email_address"
37
37
  require_relative "nylas/event"
38
- require_relative "nylas/event_collection"
39
38
  require_relative "nylas/file"
40
39
  require_relative "nylas/folder"
41
40
  require_relative "nylas/im_address"
@@ -53,14 +52,21 @@ require_relative "nylas/nylas_date"
53
52
  require_relative "nylas/when"
54
53
  require_relative "nylas/free_busy"
55
54
  require_relative "nylas/time_slot"
55
+ require_relative "nylas/open_hours"
56
56
  require_relative "nylas/event_conferencing"
57
57
  require_relative "nylas/event_conferencing_details"
58
58
  require_relative "nylas/event_conferencing_autocreate"
59
+ require_relative "nylas/event_notification"
60
+ require_relative "nylas/component"
59
61
 
60
62
  # Custom collection types
63
+ require_relative "nylas/event_collection"
61
64
  require_relative "nylas/search_collection"
62
65
  require_relative "nylas/deltas_collection"
63
66
  require_relative "nylas/free_busy_collection"
67
+ require_relative "nylas/calendar_collection"
68
+ require_relative "nylas/component_collection"
69
+ require_relative "nylas/scheduler_collection"
64
70
 
65
71
  # Models supported by the API
66
72
  require_relative "nylas/account"
@@ -77,6 +83,10 @@ require_relative "nylas/new_message"
77
83
  require_relative "nylas/raw_message"
78
84
  require_relative "nylas/thread"
79
85
  require_relative "nylas/webhook"
86
+ require_relative "nylas/scheduler"
87
+ require_relative "nylas/job_status"
88
+ require_relative "nylas/token_info"
89
+ require_relative "nylas/application_details"
80
90
 
81
91
  # Neural specific types
82
92
  require_relative "nylas/neural"
@@ -90,6 +100,10 @@ require_relative "nylas/neural_signature_contact"
90
100
  require_relative "nylas/neural_signature_extraction"
91
101
  require_relative "nylas/neural_message_options"
92
102
  require_relative "nylas/categorize"
103
+ require_relative "nylas/scheduler_config"
104
+ require_relative "nylas/scheduler_time_slot"
105
+ require_relative "nylas/scheduler_booking_request"
106
+ require_relative "nylas/scheduler_booking_confirmation"
93
107
 
94
108
  require_relative "nylas/native_authentication"
95
109
 
@@ -129,9 +143,13 @@ module Nylas
129
143
  Types.registry[:event_conferencing] = Types::ModelType.new(model: EventConferencing)
130
144
  Types.registry[:event_conferencing_details] = Types::ModelType.new(model: EventConferencingDetails)
131
145
  Types.registry[:event_conferencing_autocreate] = Types::ModelType.new(model: EventConferencingAutocreate)
146
+ Types.registry[:event_notification] = Types::ModelType.new(model: EventNotification)
132
147
  Types.registry[:neural] = Types::ModelType.new(model: Neural)
133
148
  Types.registry[:categorize] = Types::ModelType.new(model: Categorize)
134
149
  Types.registry[:neural_signature_contact] = Types::ModelType.new(model: NeuralSignatureContact)
135
150
  Types.registry[:neural_contact_link] = Types::ModelType.new(model: NeuralContactLink)
136
151
  Types.registry[:neural_contact_name] = Types::ModelType.new(model: NeuralContactName)
152
+ Types.registry[:scheduler_config] = Types::ModelType.new(model: SchedulerConfig)
153
+ Types.registry[:scheduler_time_slot] = Types::ModelType.new(model: SchedulerTimeSlot)
154
+ Types.registry[:job_status] = Types::ModelType.new(model: JobStatus)
137
155
  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.4.1
4
+ version: 5.7.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-09-27 00:00:00.000000000 Z
11
+ date: 2022-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.52.0
61
+ version: 1.24.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.52.0
68
+ version: 1.24.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop-rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 1.20.1
75
+ version: 2.7.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 1.20.1
82
+ version: 2.7.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: overcommit
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -269,9 +269,13 @@ files:
269
269
  - lib/nylas.rb
270
270
  - lib/nylas/account.rb
271
271
  - lib/nylas/api.rb
272
+ - lib/nylas/application_details.rb
272
273
  - lib/nylas/calendar.rb
274
+ - lib/nylas/calendar_collection.rb
273
275
  - lib/nylas/categorize.rb
274
276
  - lib/nylas/collection.rb
277
+ - lib/nylas/component.rb
278
+ - lib/nylas/component_collection.rb
275
279
  - lib/nylas/constraints.rb
276
280
  - lib/nylas/contact.rb
277
281
  - lib/nylas/contact_group.rb
@@ -287,6 +291,7 @@ files:
287
291
  - lib/nylas/event_conferencing.rb
288
292
  - lib/nylas/event_conferencing_autocreate.rb
289
293
  - lib/nylas/event_conferencing_details.rb
294
+ - lib/nylas/event_notification.rb
290
295
  - lib/nylas/file.rb
291
296
  - lib/nylas/filter_attributes.rb
292
297
  - lib/nylas/folder.rb
@@ -294,6 +299,7 @@ files:
294
299
  - lib/nylas/free_busy_collection.rb
295
300
  - lib/nylas/http_client.rb
296
301
  - lib/nylas/im_address.rb
302
+ - lib/nylas/job_status.rb
297
303
  - lib/nylas/label.rb
298
304
  - lib/nylas/logging.rb
299
305
  - lib/nylas/message.rb
@@ -318,6 +324,7 @@ files:
318
324
  - lib/nylas/neural_signature_extraction.rb
319
325
  - lib/nylas/new_message.rb
320
326
  - lib/nylas/nylas_date.rb
327
+ - lib/nylas/open_hours.rb
321
328
  - lib/nylas/participant.rb
322
329
  - lib/nylas/phone_number.rb
323
330
  - lib/nylas/physical_address.rb
@@ -326,10 +333,17 @@ files:
326
333
  - lib/nylas/registry.rb
327
334
  - lib/nylas/room_resource.rb
328
335
  - lib/nylas/rsvp.rb
336
+ - lib/nylas/scheduler.rb
337
+ - lib/nylas/scheduler_booking_confirmation.rb
338
+ - lib/nylas/scheduler_booking_request.rb
339
+ - lib/nylas/scheduler_collection.rb
340
+ - lib/nylas/scheduler_config.rb
341
+ - lib/nylas/scheduler_time_slot.rb
329
342
  - lib/nylas/search_collection.rb
330
343
  - lib/nylas/thread.rb
331
344
  - lib/nylas/time_slot.rb
332
345
  - lib/nylas/timespan.rb
346
+ - lib/nylas/token_info.rb
333
347
  - lib/nylas/types.rb
334
348
  - lib/nylas/version.rb
335
349
  - lib/nylas/web_page.rb
@@ -360,7 +374,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
360
374
  - !ruby/object:Gem::Version
361
375
  version: '0'
362
376
  requirements: []
363
- rubygems_version: 3.1.6
377
+ rubygems_version: 3.2.17
364
378
  signing_key:
365
379
  specification_version: 4
366
380
  summary: Gem for interacting with the Nylas API