Class: ConnectorsSdk::Office365::CustomClient

Inherits:
Base::CustomClient show all
Defined in:
lib/connectors_sdk/office365/custom_client.rb

Defined Under Namespace

Modules: Office365DownloadParamsEncoder Classes: ClientError, Office365InvalidCursorsError

Constant Summary collapse

OFFICE365_PERMISSION_SYNC_TIME_SLA =
24.hours
BASE_URL =
'https://graph.microsoft.com/v1.0/'.freeze

Constants inherited from Base::CustomClient

Base::CustomClient::MAX_RETRIES

Instance Attribute Summary collapse

Attributes inherited from Base::CustomClient

#base_url, #ensure_fresh_auth, #middleware

Instance Method Summary collapse

Methods inherited from Base::CustomClient

#additional_middleware, #default_middleware, #http_client, #http_client!, #middleware!, #retry_config

Constructor Details

#initialize(access_token:, cursors: {}, ensure_fresh_auth: nil) ⇒ CustomClient

Returns a new instance of CustomClient.



52
53
54
55
56
# File 'lib/connectors_sdk/office365/custom_client.rb', line 52

def initialize(access_token:, cursors: {}, ensure_fresh_auth: nil)
  @access_token = access_token
  @cursors = cursors || {}
  super(:ensure_fresh_auth => ensure_fresh_auth)
end

Instance Attribute Details

#access_tokenObject (readonly)

Returns the value of attribute access_token.



47
48
49
# File 'lib/connectors_sdk/office365/custom_client.rb', line 47

def access_token
  @access_token
end

#cursorsObject

Returns the value of attribute cursors.



48
49
50
# File 'lib/connectors_sdk/office365/custom_client.rb', line 48

def cursors
  @cursors
end

Instance Method Details

#download_item(download_url) ⇒ Object



183
184
185
186
187
188
# File 'lib/connectors_sdk/office365/custom_client.rb', line 183

def download_item(download_url)
  request(:url => download_url) do |request|
    request.options.params_encoder = Office365DownloadParamsEncoder
    request.options.timeout = 30
  end.body
end


169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/connectors_sdk/office365/custom_client.rb', line 169

def exhaustively_get_delta_link(drive_id)
  endpoint = "drives/#{drive_id}/root/delta"

  Connectors::Stats.measure('custom_client.office365.exhaustively_get_delta_link') do
    response = request_endpoint(:endpoint => endpoint, :query_params => { :'$select' => 'id' })

    while next_link = response['@odata.nextLink']
      response = request_json(:url => next_link)
    end

    response['@odata.deltaLink'].split('?').first
  end
end


165
166
167
# File 'lib/connectors_sdk/office365/custom_client.rb', line 165

def get_latest_delta_link(drive_id)
  cursors[drive_id] || exhaustively_get_delta_link(drive_id)
end

#group_root_site(group_id, fields: []) ⇒ Object



92
93
94
95
96
# File 'lib/connectors_sdk/office365/custom_client.rb', line 92

def group_root_site(group_id, fields: [])
  query_params = transform_fields_to_request_query_params(fields)

  request_endpoint(:endpoint => "groups/#{group_id}/sites/root", :query_params => query_params)
end

#groups(fields: []) ⇒ Object



88
89
90
# File 'lib/connectors_sdk/office365/custom_client.rb', line 88

def groups(fields: [])
  request_all(:endpoint => 'groups/', :fields => fields)
end

#item_permissions(drive_id, item_id) ⇒ Object



134
135
136
# File 'lib/connectors_sdk/office365/custom_client.rb', line 134

def item_permissions(drive_id, item_id)
  request_endpoint(:endpoint => "drives/#{drive_id}/items/#{item_id}/permissions").value
end

#list_changes(drive_id:, start_delta_link: nil, last_modified: nil) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/connectors_sdk/office365/custom_client.rb', line 138

def list_changes(drive_id:, start_delta_link: nil, last_modified: nil)
  query_params = { :'$select' => %w(id content.downloadUrl lastModifiedDateTime lastModifiedBy root deleted file folder package name webUrl createdBy createdDateTime size).join(',') }
  response =
    if start_delta_link.nil?
      endpoint = "drives/#{drive_id}/root/delta"
      request_endpoint(:endpoint => endpoint, :query_params => query_params)
    else
      request_json(:url => start_delta_link, :query_params => query_params)
    end

  loop do
    response.value.each do |change|
      # MSFT Graph API does not allow us to view "changes" in chronological order, so if there is no cursor,
      # we have to iterate through all changes and cherry-pick the ones that are past the `last_modified` Time
      # since to get another cursor, we would have to go through all the changes anyway
      next if last_modified.present? && Time.parse(change.lastModifiedDateTime) < last_modified
      next if change.root # We don't want to index the root of the drive
      yield change
    end

    break if response['@odata.nextLink'].nil?
    response = request_json(:url => response['@odata.nextLink'])
  end

  cursors[drive_id] = response['@odata.deltaLink']
end

#list_items(drive_id, fields: []) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/connectors_sdk/office365/custom_client.rb', line 117

def list_items(drive_id, fields: [])
  # MSFT Graph API does not have a recursive list items, have to do this dfs style
  stack = [get_root_item(drive_id, ['id']).id]
  # We rely on the id field below to perform our DFS
  fields_with_id = fields.any? ? fields | ['id'] : fields
  while stack.any?
    folder_id = stack.pop
    item_children(drive_id, folder_id, :fields => fields_with_id) do |item|
      if item.folder
        stack << item.id
      end
      yield item
    end

  end
end

#meObject



63
64
65
# File 'lib/connectors_sdk/office365/custom_client.rb', line 63

def me
  request_endpoint(:endpoint => 'me')
end

#one_drive_drives(fields: []) ⇒ Object



67
68
69
70
71
# File 'lib/connectors_sdk/office365/custom_client.rb', line 67

def one_drive_drives(fields: [])
  query_params = transform_fields_to_request_query_params(fields)
  response = request_endpoint(:endpoint => 'me/drives/', :query_params => query_params)
  response.value
end

#share_point_drives(fields: []) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/connectors_sdk/office365/custom_client.rb', line 73

def share_point_drives(fields: [])
  # When new Private Team site is created in SharePoint, permissions take some time to propagate, therefore
  # this site won't be indexed by us until propagation happens. This code tries to also fetch sites from
  # recently created groups (new Private Team site will be there) to reduce friction and index this site
  # earlier.
  # See: https://github.com/elastic/ent-search/pull/3581
  share_point_sites = (sites(:fields => %w[id,name]) + recent_share_point_group_sites(:fields => %w[id,name]))

  share_point_sites
    .uniq(&:id)
    .map { |site| site_drives(site, :fields => fields) }
    .flatten
    .compact
end

#site_drives(site, fields: []) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/connectors_sdk/office365/custom_client.rb', line 105

def site_drives(site, fields: [])
  document_libraries(
    request_all(:endpoint => "sites/#{site.id}/drives/", :fields => fields)
  ).map do |drive|
    drive.site_name = site.name
    drive
  end
rescue ClientError => e
  ConnectorsShared::Logger.info("Received response of #{e.status_code} trying to get drive for Site with Id = #{site_id}: #{e.message}")
  nil
end

#sites(fields: []) ⇒ Object



98
99
100
101
102
103
# File 'lib/connectors_sdk/office365/custom_client.rb', line 98

def sites(fields: [])
  # This empty search string ends up returning all sites. If we leave it off, the API returns a 400
  # I explicity set the page size here (via :top) because otherwise the API just returns the first ten and
  # does not provide any additional pages.
  request_all(:endpoint => 'sites/', :fields => fields, :additional_query_params => { :search => '', :top => 10 })
end

#update_auth_data!(new_access_token) ⇒ Object



58
59
60
61
# File 'lib/connectors_sdk/office365/custom_client.rb', line 58

def update_auth_data!(new_access_token)
  @access_token = new_access_token
  self
end

#user_groups(user_id, fields = []) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/connectors_sdk/office365/custom_client.rb', line 190

def user_groups(user_id, fields = [])
  (
    request_all(
      :endpoint => "users/#{user_id}/transitiveMemberOf",
      :fields => fields
    ) +
      request_all(
        :endpoint => "users/#{user_id}/ownedObjects",
        :fields => fields
      ).select { |next_object| next_object['@odata.type'] == '#microsoft.graph.group' }
  ).uniq
end