multiwoven-integrations 0.1.41 → 0.1.42

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: 82b67da3db5fd718642d785a6c88d95aab50098e900ace51d275839b0282ce1d
4
- data.tar.gz: 5e749c3149f853de00482ddb1899b622a062cf96b3ee22dfd428e0fa94a68ca9
3
+ metadata.gz: eee51b7ba03e877f2765da694f9ca7b4ede8e44e07ca74931d808f79fb828c06
4
+ data.tar.gz: 21a23a656e09175222172eea24e562c95ccc97e7bebe92443cc60678d68050bf
5
5
  SHA512:
6
- metadata.gz: 18fc7eb3472d27029851e6768cec57b9d1cf0c13dd462938a76d7ecc3770f041be0f5c5de3609d5270869358e5080af969bca7296ee11bfb41244b40aa05bcf5
7
- data.tar.gz: aaa27f548de6c20a6444644fe784ee708b7f6b8f9113812ab046d8b72ea161e114e16cc5d524a196aa479c707d3055143952658fd018a026e484905a2b30b7c4
6
+ metadata.gz: 388d743e298e3296fbd9bd12e5d29037d72bf4912f93ae8ae8b9d7f5285dbb2d39f39f1500f6ee3b6214e186564287eec8c3fe14d66f55cc53861585e3929e33
7
+ data.tar.gz: e527726e1e69c57c07d7d6ab28194f2a84dfbbffb941f61e2b5fca927cecf486edcb7fa2cecbbcc8ccc1713c396e1723161e5ea55f0cc8d310ce2d888f6de845
@@ -95,7 +95,8 @@ module Multiwoven
95
95
  request_rate_limit: stream_json["request_rate_limit"].to_i,
96
96
  request_rate_limit_unit: stream_json["request_rate_limit_unit"] || "minute",
97
97
  request_rate_concurrency: stream_json["request_rate_concurrency"].to_i,
98
- supported_sync_modes: stream_json["supported_sync_modes"]
98
+ supported_sync_modes: stream_json["supported_sync_modes"],
99
+ schema_mode: stream_json["schema_mode"]
99
100
  )
100
101
  end
101
102
  end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven::Integrations::Destination
4
+ module Sftp
5
+ include Multiwoven::Integrations::Core
6
+ class Client < DestinationConnector
7
+ prepend Multiwoven::Integrations::Core::Fullrefresher
8
+ prepend Multiwoven::Integrations::Core::RateLimiter
9
+
10
+ def check_connection(connection_config)
11
+ connection_config = connection_config.with_indifferent_access
12
+ with_sftp_client(connection_config) do |sftp|
13
+ stream = SecureRandom.uuid
14
+ test_path = "/path/to/test/#{stream}"
15
+ test_file_operations(sftp, test_path)
16
+ return success_status
17
+ end
18
+ rescue StandardError => e
19
+ handle_exception("SFTP:CHECK_CONNECTION:EXCEPTION", "error", e)
20
+ failure_status(e)
21
+ end
22
+
23
+ def discover(_connection_config = nil)
24
+ catalog_json = read_json(CATALOG_SPEC_PATH)
25
+
26
+ catalog = build_catalog(catalog_json)
27
+
28
+ catalog.to_multiwoven_message
29
+ rescue StandardError => e
30
+ handle_exception(
31
+ "SFTP:DISCOVER:EXCEPTION",
32
+ "error",
33
+ e
34
+ )
35
+ end
36
+
37
+ def write(sync_config, records, _action = "insert")
38
+ connection_config = sync_config.destination.connection_specification.with_indifferent_access
39
+ file_path = generate_file_path(sync_config)
40
+ csv_content = generate_csv_content(records)
41
+ write_success = 0
42
+ write_failure = 0
43
+ # 10000 records in single
44
+ with_sftp_client(connection_config) do |sftp|
45
+ sftp.file.open(file_path, "w") { |file| file.puts(csv_content) }
46
+ write_success += records.size
47
+ rescue StandardError => e
48
+ handle_exception("SFTP:RECORD:WRITE:EXCEPTION", "error", e)
49
+ write_failure += records.size
50
+ end
51
+ tracking_message(write_success, write_failure)
52
+ rescue StandardError => e
53
+ handle_exception(
54
+ "SFTP:WRITE:EXCEPTION",
55
+ "error",
56
+ e
57
+ )
58
+ end
59
+
60
+ def clear_all_records(sync_config)
61
+ connection_specification = sync_config.destination.connection_specification.with_indifferent_access
62
+ with_sftp_client(connection_specification) do |sftp|
63
+ files = sftp.dir.glob(connection_specification[:destination_path], "*")
64
+
65
+ files.each do |file|
66
+ sftp.remove!(File.join(connection_specification[:destination_path], file.name))
67
+ end
68
+ if sftp.dir.entries(connection_specification[:destination_path]).size == 2
69
+ control_message("Successfully cleared data.", "succeeded")
70
+ else
71
+ control_message("Failed to clear data.", "failed")
72
+ end
73
+ end
74
+ rescue StandardError => e
75
+ control_message(e.message, "failed")
76
+ end
77
+
78
+ private
79
+
80
+ def generate_file_path(sync_config)
81
+ timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
82
+ file_name = "#{sync_config.stream.name}_#{timestamp}.csv"
83
+ File.join(sync_config.destination.connection_specification[:destination_path], file_name)
84
+ end
85
+
86
+ def generate_csv_content(records)
87
+ CSV.generate do |csv|
88
+ headers = records.first.keys
89
+ csv << headers
90
+ records.each { |record| csv << record.values_at(*headers) }
91
+ end
92
+ end
93
+
94
+ def tracking_message(success, failure)
95
+ Multiwoven::Integrations::Protocol::TrackingMessage.new(
96
+ success: success, failed: failure
97
+ ).to_multiwoven_message
98
+ end
99
+
100
+ def with_sftp_client(connection_config, &block)
101
+ Net::SFTP.start(
102
+ connection_config[:host],
103
+ connection_config[:username],
104
+ password: connection_config[:password],
105
+ port: connection_config.fetch(:port, 22), &block
106
+ )
107
+ end
108
+
109
+ def test_file_operations(sftp, test_path)
110
+ sftp.file.open(test_path, "w") { |file| file.puts("connection_check") }
111
+ sftp.remove!(test_path)
112
+ end
113
+
114
+ def control_message(message, status)
115
+ ControlMessage.new(
116
+ type: "full_refresh",
117
+ emitted_at: Time.now.to_i,
118
+ status: ConnectionStatusType[status],
119
+ meta: { detail: message }
120
+ ).to_multiwoven_message
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,16 @@
1
+ {
2
+ "request_rate_limit": 600,
3
+ "request_rate_limit_unit": "minute",
4
+ "request_rate_concurrency": 10,
5
+ "streams": [
6
+ {
7
+ "name": "sftp",
8
+ "batch_support": true,
9
+ "batch_size": 10000,
10
+ "action": "create",
11
+ "schema_mode": ["schemaless"],
12
+ "json_schema": {},
13
+ "supported_sync_modes": ["full_refresh","incremental"]
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "data": {
3
+ "name": "Sftp",
4
+ "title": "SFTP",
5
+ "connector_type": "destination",
6
+ "connectorSubtype": "file",
7
+ "category": "File Storage",
8
+ "documentation_url": "https://docs.mutliwoven.com",
9
+ "github_issue_label": "destination-sftp",
10
+ "icon": "icon.svg",
11
+ "license": "MIT",
12
+ "release_stage": "alpha",
13
+ "support_level": "community",
14
+ "tags": ["language:ruby", "multiwoven"]
15
+ }
16
+ }
@@ -0,0 +1,44 @@
1
+ {
2
+ "documentation_url": "https://docs.multiwoven.com/integrations/destination/klaviyo",
3
+ "stream_type": "static",
4
+ "connection_specification": {
5
+ "$schema": "http://json-schema.org/draft-07/schema#",
6
+ "title": "SFTP",
7
+ "required": ["host", "username", "password", "destination_path"],
8
+ "properties": {
9
+ "host": {
10
+ "title": "Host",
11
+ "description": "Hostname of the SFTP server.",
12
+ "type": "string",
13
+ "order": 0
14
+ },
15
+ "port": {
16
+ "title": "Port",
17
+ "description": "Port of the SFTP server.",
18
+ "type": "integer",
19
+ "minimum": 0,
20
+ "maximum": 65536,
21
+ "default": 22,
22
+ "order": 1
23
+ },
24
+ "username": {
25
+ "title": "User Name",
26
+ "description": "Username to use to access the SFTP server.",
27
+ "type": "string",
28
+ "order": 2
29
+ },
30
+ "password": {
31
+ "title": "Password",
32
+ "description": "Password associated with the username.",
33
+ "type": "string",
34
+ "order": 3
35
+ },
36
+ "destination_path": {
37
+ "title": "Destination path",
38
+ "type": "string",
39
+ "description": "Path to the directory where files will be written.",
40
+ "order": 4
41
+ }
42
+ }
43
+ }
44
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" fill="none"><g clip-path="url(#a)"><path fill="#615EFF" d="M200.745 218.706a12.051 12.051 0 0 1-3.483 8.475 11.837 11.837 0 0 1-8.4 3.514H62.072c-3.15 0-6.173-1.261-8.403-3.507a12.053 12.053 0 0 1-3.49-8.472V31.485a12.08 12.08 0 0 1 .903-4.593 11.996 11.996 0 0 1 2.578-3.894 11.875 11.875 0 0 1 3.86-2.6 11.791 11.791 0 0 1 4.552-.912h81.371l57.302 58.96v140.26Z"/><path fill="#fff" d="M83.868 156.832c-.142-1.429-.75-2.539-1.822-3.33-1.074-.792-2.53-1.187-4.37-1.187-1.25 0-2.305.177-3.166.531-.861.343-1.522.821-1.981 1.435a3.457 3.457 0 0 0-.673 2.09c-.023.65.112 1.217.407 1.701.307.484.725.903 1.256 1.258.53.342 1.144.643 1.84.903a19.02 19.02 0 0 0 2.229.638l3.255.779c1.58.354 3.03.827 4.352 1.417 1.32.591 2.464 1.317 3.431 2.179a9.057 9.057 0 0 1 2.247 3.047c.542 1.169.82 2.509.831 4.021-.011 2.22-.578 4.145-1.698 5.775-1.109 1.617-2.712 2.875-4.811 3.773-2.088.885-4.606 1.328-7.554 1.328-2.925 0-5.472-.449-7.642-1.346-2.158-.898-3.845-2.226-5.06-3.986-1.202-1.771-1.833-3.962-1.892-6.572h7.412c.082 1.217.43 2.232 1.044 3.047.625.803 1.456 1.411 2.494 1.825 1.05.401 2.235.602 3.555.602 1.298 0 2.424-.189 3.38-.567.966-.378 1.715-.903 2.246-1.576.53-.673.796-1.447.796-2.321 0-.815-.242-1.5-.725-2.055-.472-.555-1.168-1.027-2.088-1.417-.908-.39-2.022-.744-3.343-1.063l-3.945-.992c-3.054-.744-5.466-1.907-7.235-3.489-1.77-1.583-2.648-3.714-2.636-6.395-.012-2.196.572-4.116 1.751-5.757 1.192-1.641 2.825-2.923 4.9-3.844 2.076-.921 4.435-1.382 7.076-1.382 2.69 0 5.036.461 7.04 1.382 2.018.921 3.586 2.203 4.706 3.844 1.12 1.641 1.699 3.543 1.734 5.704h-7.341Zm12.988 25.844v-36.278h23.988v6.324h-16.328v8.645h14.736v6.324h-14.736v14.985h-7.66Zm27.76-29.954v-6.324h29.754v6.324h-11.091v29.954h-7.571v-29.954h-11.092Zm34.654 29.954v-36.278h14.294c2.748 0 5.089.526 7.023 1.577 1.934 1.039 3.408 2.486 4.422 4.34 1.026 1.842 1.539 3.968 1.539 6.377s-.519 4.535-1.557 6.377c-1.037 1.842-2.541 3.277-4.51 4.304-1.958 1.028-4.329 1.541-7.112 1.541h-9.11v-6.146h7.872c1.474 0 2.689-.254 3.644-.762.967-.52 1.686-1.234 2.158-2.143.484-.921.725-1.978.725-3.171 0-1.205-.241-2.256-.725-3.153-.472-.91-1.191-1.612-2.158-2.108-.967-.508-2.194-.762-3.679-.762h-5.166v30.007h-7.66Z"/><path fill="#1A194D" d="m149.75 76.907 50.996 49.177V78.101h-45.173a11.33 11.33 0 0 1-5.643-1.433l-.18.24Z" opacity=".3"/><path fill="#C5C4FF" d="M200.746 78.35h-45.297a11.836 11.836 0 0 1-8.399-3.514 12.055 12.055 0 0 1-3.484-8.475v-47.2l57.18 59.189Z"/></g><defs><clipPath id="a"><path fill="#fff" d="M50 19h151v212H50z"/></clipPath></defs></svg>
@@ -24,6 +24,7 @@ module Multiwoven
24
24
  )
25
25
  LogLevel = Types::String.enum("fatal", "error", "warn", "info", "debug", "trace")
26
26
  RequestRateLimitingUnit = Types::String.default("minute").enum("minute", "hour", "day")
27
+ SchemaMode = Types::String.enum("schema", "schemaless")
27
28
 
28
29
  class ProtocolModel < Dry::Struct
29
30
  extend Multiwoven::Integrations::Core::Utils
@@ -124,6 +125,7 @@ module Multiwoven
124
125
  attribute? :request_rate_limit, Types::Integer
125
126
  attribute? :request_rate_limit_unit, RequestRateLimitingUnit
126
127
  attribute? :request_rate_concurrency, Types::Integer
128
+ attribute? :schema_mode, Types::Array.of(SchemaMode).optional.default(["schema"])
127
129
 
128
130
  def rate_limit_unit_seconds
129
131
  case request_rate_limit_unit
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Multiwoven
4
4
  module Integrations
5
- VERSION = "0.1.41"
5
+ VERSION = "0.1.42"
6
6
 
7
7
  ENABLED_SOURCES = %w[
8
8
  Snowflake
@@ -23,6 +23,7 @@ module Multiwoven
23
23
  Airtable
24
24
  Stripe
25
25
  SalesforceConsumerGoodsCloud
26
+ Sftp
26
27
  ].freeze
27
28
  end
28
29
  end
@@ -19,6 +19,9 @@ require "hubspot-api-client"
19
19
  require "google/apis/sheets_v4"
20
20
  require "stringio"
21
21
  require "stripe"
22
+ require "net/sftp"
23
+ require "csv"
24
+ require "securerandom"
22
25
 
23
26
  # Service
24
27
  require_relative "integrations/config"
@@ -54,6 +57,7 @@ require_relative "integrations/destination/google_sheets/client"
54
57
  require_relative "integrations/destination/airtable/client"
55
58
  require_relative "integrations/destination/stripe/client"
56
59
  require_relative "integrations/destination/salesforce_consumer_goods_cloud/client"
60
+ require_relative "integrations/destination/sftp/client"
57
61
 
58
62
  module Multiwoven
59
63
  module Integrations
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.1.41
4
+ version: 0.1.42
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: 2024-03-24 00:00:00.000000000 Z
11
+ date: 2024-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: csv
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: dry-schema
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +150,20 @@ dependencies:
136
150
  - - ">="
137
151
  - !ruby/object:Gem::Version
138
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: net-sftp
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
139
167
  - !ruby/object:Gem::Dependency
140
168
  name: pg
141
169
  requirement: !ruby/object:Gem::Requirement
@@ -395,6 +423,11 @@ files:
395
423
  - lib/multiwoven/integrations/destination/salesforce_crm/config/meta.json
396
424
  - lib/multiwoven/integrations/destination/salesforce_crm/config/spec.json
397
425
  - lib/multiwoven/integrations/destination/salesforce_crm/icon.svg
426
+ - lib/multiwoven/integrations/destination/sftp/client.rb
427
+ - lib/multiwoven/integrations/destination/sftp/config/catalog.json
428
+ - lib/multiwoven/integrations/destination/sftp/config/meta.json
429
+ - lib/multiwoven/integrations/destination/sftp/config/spec.json
430
+ - lib/multiwoven/integrations/destination/sftp/icon.svg
398
431
  - lib/multiwoven/integrations/destination/slack/client.rb
399
432
  - lib/multiwoven/integrations/destination/slack/config/catalog.json
400
433
  - lib/multiwoven/integrations/destination/slack/config/meta.json