multiwoven-integrations 0.38.0 → 0.38.1
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 828f206c7576ddd3e84774cc75175213d1bef9a78df725564c67ac37d5e474d8
|
|
4
|
+
data.tar.gz: 98b0930cef5d402c99ba5272a97cb918bb301573de8202cfaafe54d825f817e4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: afd08217ce63822cf47858221c70cda09b9755b17ce2e08e6fe7156b49b74a9c6c3525e52c2f07b6946ef27d7eccd0fe113846dd51bfa48467f3c8be1641c341
|
|
7
|
+
data.tar.gz: f0c1d17204b01e640d49ea0cb8747baead11ecbea7c4dd4e1c7a3aa9a938e8c60ca0cbb48044fa4a3b1aaed6cca51546928be77c206c4a263e965fca77cf74fa
|
|
@@ -82,6 +82,7 @@ module Multiwoven::Integrations::Source
|
|
|
82
82
|
@data_type = connection_config[:data_type]
|
|
83
83
|
@file_name = connection_config[:file_name]
|
|
84
84
|
@share_url = connection_config[:share_url]
|
|
85
|
+
@is_recursive = [true, "true"].include?(connection_config[:is_recursive])
|
|
85
86
|
stored_token = @connector_instance&.configuration&.dig("access_token")
|
|
86
87
|
@access_token = stored_token.presence || refresh_access_token
|
|
87
88
|
end
|
|
@@ -173,11 +174,12 @@ module Multiwoven::Integrations::Source
|
|
|
173
174
|
|
|
174
175
|
def list_files_in_folder(_connection_config)
|
|
175
176
|
files_in_folder.map do |file|
|
|
177
|
+
relative_path = relative_file_path(file)
|
|
176
178
|
RecordMessage.new(
|
|
177
179
|
data: {
|
|
178
180
|
element_id: file["id"],
|
|
179
181
|
file_name: file["name"],
|
|
180
|
-
file_path:
|
|
182
|
+
file_path: relative_path,
|
|
181
183
|
size: file["size"],
|
|
182
184
|
file_type: File.extname(file["name"]).sub(".", ""),
|
|
183
185
|
created_date: file["createdDateTime"],
|
|
@@ -190,10 +192,12 @@ module Multiwoven::Integrations::Source
|
|
|
190
192
|
end
|
|
191
193
|
|
|
192
194
|
def download_unstructured_file(_connection_config, file_path, sync_id)
|
|
193
|
-
|
|
194
|
-
file_item =
|
|
195
|
+
lookup_path = resolve_download_file_name(file_path)
|
|
196
|
+
file_item = find_file_item(lookup_path)
|
|
195
197
|
raise StandardError, "File not found." if file_item.nil?
|
|
196
198
|
|
|
199
|
+
file_name = file_item["name"]
|
|
200
|
+
relative_path = relative_file_path(file_item)
|
|
197
201
|
local_path = download_file_to_local(
|
|
198
202
|
file_name,
|
|
199
203
|
sync_id,
|
|
@@ -206,7 +210,7 @@ module Multiwoven::Integrations::Source
|
|
|
206
210
|
element_id: file_item["id"],
|
|
207
211
|
local_path: local_path,
|
|
208
212
|
file_name: file_name,
|
|
209
|
-
file_path:
|
|
213
|
+
file_path: relative_path,
|
|
210
214
|
size: file_item["size"],
|
|
211
215
|
file_type: File.extname(file_name).sub(".", ""),
|
|
212
216
|
created_date: file_item["createdDateTime"],
|
|
@@ -220,19 +224,35 @@ module Multiwoven::Integrations::Source
|
|
|
220
224
|
def files_in_folder
|
|
221
225
|
records = fetch_list_items
|
|
222
226
|
records["value"].select do |item|
|
|
223
|
-
item["folder"].blank? && matching_file_name?(item["name"])
|
|
227
|
+
item["folder"].blank? && matching_file_name?(item["name"], relative_file_path(item))
|
|
224
228
|
end
|
|
225
229
|
end
|
|
226
230
|
|
|
231
|
+
def find_file_item(lookup_path)
|
|
232
|
+
files = files_in_folder
|
|
233
|
+
exact_match = files.find do |item|
|
|
234
|
+
relative_path = relative_file_path(item)
|
|
235
|
+
relative_path == lookup_path
|
|
236
|
+
end
|
|
237
|
+
return exact_match if exact_match
|
|
238
|
+
return if lookup_path.include?("/")
|
|
239
|
+
|
|
240
|
+
files.find { |item| item["name"] == lookup_path }
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def relative_file_path(file)
|
|
244
|
+
file["relative_path"].presence || file["name"]
|
|
245
|
+
end
|
|
246
|
+
|
|
227
247
|
def resolve_download_file_name(file_path)
|
|
228
|
-
return
|
|
248
|
+
return file_path.to_s.strip unless file_path.to_s.start_with?("http")
|
|
229
249
|
|
|
230
250
|
@file_name.to_s.strip.presence || File.basename(file_path)
|
|
231
251
|
end
|
|
232
252
|
|
|
233
|
-
def matching_file_name?(name)
|
|
253
|
+
def matching_file_name?(name, relative_path = nil)
|
|
234
254
|
configured_name = @file_name.to_s.strip
|
|
235
|
-
configured_name.blank? || configured_name == name
|
|
255
|
+
configured_name.blank? || configured_name == name || configured_name == relative_path
|
|
236
256
|
end
|
|
237
257
|
|
|
238
258
|
def discover_stream_for_file(conn, file)
|
|
@@ -240,7 +260,7 @@ module Multiwoven::Integrations::Source
|
|
|
240
260
|
columns = build_discover_columns(describe_results)
|
|
241
261
|
|
|
242
262
|
Multiwoven::Integrations::Protocol::Stream.new(
|
|
243
|
-
name: stream_name_for(file
|
|
263
|
+
name: stream_name_for(file),
|
|
244
264
|
action: StreamAction["fetch"],
|
|
245
265
|
json_schema: convert_to_json_schema(columns)
|
|
246
266
|
)
|
|
@@ -289,9 +309,10 @@ module Multiwoven::Integrations::Source
|
|
|
289
309
|
def query(connection, query)
|
|
290
310
|
local_file = nil
|
|
291
311
|
file_name = extract_file_name_from_query(query)
|
|
312
|
+
local_basename = File.basename(file_name)
|
|
292
313
|
local_file = download_file_to_local(file_name, @sync_id)
|
|
293
314
|
|
|
294
|
-
file = read_local_file(connection,
|
|
315
|
+
file = read_local_file(connection, local_basename, local_file)
|
|
295
316
|
query = apply_local_file_to_query(query, file)
|
|
296
317
|
get_results(connection, query).map do |row|
|
|
297
318
|
RecordMessage.new(data: row, emitted_at: Time.now.to_i).to_multiwoven_message
|
|
@@ -393,7 +414,8 @@ module Multiwoven::Integrations::Source
|
|
|
393
414
|
end
|
|
394
415
|
|
|
395
416
|
def single_file_item_url(file_name)
|
|
396
|
-
|
|
417
|
+
# Preserve path separators for nested files; encode other unsafe chars.
|
|
418
|
+
encoded_file = file_name.to_s.split("/").map { |segment| URI::DEFAULT_PARSER.escape(segment) }.join("/")
|
|
397
419
|
|
|
398
420
|
if @share_url.present?
|
|
399
421
|
shared = shared_folder_reference
|
|
@@ -440,7 +462,35 @@ module Multiwoven::Integrations::Source
|
|
|
440
462
|
|
|
441
463
|
return { "value" => [fetch_shared_item_metadata] } if @share_url.present? && shared_folder_reference[:is_file]
|
|
442
464
|
|
|
443
|
-
|
|
465
|
+
collect_files_from_folder(list_items_url, recursive: @is_recursive)
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
# Lists files under the configured folder. When recursive is true, BFS over
|
|
469
|
+
# /children so nested folder files are included in syncs.
|
|
470
|
+
def collect_files_from_folder(root_url, recursive: false)
|
|
471
|
+
files = []
|
|
472
|
+
queue = [[root_url, ""]]
|
|
473
|
+
|
|
474
|
+
until queue.empty?
|
|
475
|
+
url, prefix = queue.shift
|
|
476
|
+
page = paginated_graph_collection(url)
|
|
477
|
+
|
|
478
|
+
page["value"].each do |item|
|
|
479
|
+
relative_path = prefix.empty? ? item["name"].to_s : "#{prefix}/#{item["name"]}"
|
|
480
|
+
|
|
481
|
+
if item["folder"].present?
|
|
482
|
+
next unless recursive
|
|
483
|
+
|
|
484
|
+
drive_id = item.dig("parentReference", "driveId") || @drive_id
|
|
485
|
+
queue << ["#{drive_item_url(drive_id, item["id"])}/children", relative_path]
|
|
486
|
+
else
|
|
487
|
+
item["relative_path"] = relative_path
|
|
488
|
+
files << item
|
|
489
|
+
end
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
{ "value" => files }
|
|
444
494
|
end
|
|
445
495
|
|
|
446
496
|
def fetch_shared_item_metadata
|
|
@@ -460,7 +510,9 @@ module Multiwoven::Integrations::Source
|
|
|
460
510
|
response = microsoft_graph_request(single_file_item_url(@file_name))
|
|
461
511
|
raise graph_api_error(response.body) unless success?(response)
|
|
462
512
|
|
|
463
|
-
JSON.parse(response.body)
|
|
513
|
+
item = JSON.parse(response.body)
|
|
514
|
+
item["relative_path"] = @file_name.to_s.strip
|
|
515
|
+
item
|
|
464
516
|
end
|
|
465
517
|
|
|
466
518
|
def paginated_graph_collection(url)
|
|
@@ -498,14 +550,15 @@ module Multiwoven::Integrations::Source
|
|
|
498
550
|
records["value"].select do |record|
|
|
499
551
|
record["folder"].blank? &&
|
|
500
552
|
SPREADSHEET_EXTENSIONS.include?(File.extname(record["name"].to_s).downcase) &&
|
|
501
|
-
matching_file_name?(record["name"])
|
|
553
|
+
matching_file_name?(record["name"], relative_file_path(record))
|
|
502
554
|
end
|
|
503
555
|
end
|
|
504
556
|
|
|
505
|
-
# Keep the
|
|
506
|
-
# `SELECT * FROM ${stream.name}`, and read_local_file keys off
|
|
507
|
-
|
|
508
|
-
|
|
557
|
+
# Keep the relative path (with extension) in the stream name — TableSelector
|
|
558
|
+
# generates `SELECT * FROM ${stream.name}`, and read_local_file keys off
|
|
559
|
+
# File.extname. Relative paths also disambiguate nested duplicates.
|
|
560
|
+
def stream_name_for(file)
|
|
561
|
+
relative_file_path(file)
|
|
509
562
|
end
|
|
510
563
|
|
|
511
564
|
def encode_sharing_url(url)
|
|
@@ -45,6 +45,12 @@
|
|
|
45
45
|
"title": "Share URL",
|
|
46
46
|
"description": "OneDrive or SharePoint sharing link for the folder to read from, skip if using User Name to access Root Folder."
|
|
47
47
|
},
|
|
48
|
+
"is_recursive": {
|
|
49
|
+
"type": "boolean",
|
|
50
|
+
"title": "Enable recursive",
|
|
51
|
+
"description": "Enables recursive folder traversal. When true, all files and subfolders are read. Default is false, reading only the specified folder.",
|
|
52
|
+
"default": false
|
|
53
|
+
},
|
|
48
54
|
"file_name": {
|
|
49
55
|
"type": "string",
|
|
50
56
|
"title": "File Name",
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multiwoven-integrations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.38.
|
|
4
|
+
version: 0.38.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Subin T P
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|