multiwoven-integrations 0.1.1 → 0.1.6

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.vscode/settings.json +5 -0
  3. data/lib/multiwoven/integrations/core/base_connector.rb +3 -3
  4. data/lib/multiwoven/integrations/core/constants.rb +2 -0
  5. data/lib/multiwoven/integrations/core/source_connector.rb +17 -0
  6. data/lib/multiwoven/integrations/core/utils.rb +8 -0
  7. data/lib/multiwoven/integrations/destination/facebook_custom_audience/client.rb +123 -0
  8. data/lib/multiwoven/integrations/destination/facebook_custom_audience/config/catalog.json +38 -0
  9. data/lib/multiwoven/integrations/destination/facebook_custom_audience/config/meta.json +15 -0
  10. data/lib/multiwoven/integrations/destination/facebook_custom_audience/config/spec.json +22 -0
  11. data/lib/multiwoven/integrations/destination/klaviyo/client.rb +11 -3
  12. data/lib/multiwoven/integrations/destination/klaviyo/config/catalog.json +86 -88
  13. data/lib/multiwoven/integrations/destination/klaviyo/config/meta.json +1 -1
  14. data/lib/multiwoven/integrations/destination/klaviyo/config/spec.json +2 -2
  15. data/lib/multiwoven/integrations/destination/salesforce_crm/client.rb +127 -0
  16. data/lib/multiwoven/integrations/destination/salesforce_crm/config/catalog.json +317 -0
  17. data/lib/multiwoven/integrations/destination/salesforce_crm/config/meta.json +15 -0
  18. data/lib/multiwoven/integrations/destination/salesforce_crm/config/spec.json +37 -0
  19. data/lib/multiwoven/integrations/destination/slack/client.rb +125 -0
  20. data/lib/multiwoven/integrations/destination/slack/config/catalog.json +71 -0
  21. data/lib/multiwoven/integrations/destination/slack/config/meta.json +14 -0
  22. data/lib/multiwoven/integrations/destination/slack/config/spec.json +22 -0
  23. data/lib/multiwoven/integrations/protocol/protocol.rb +2 -0
  24. data/lib/multiwoven/integrations/rollout.rb +4 -1
  25. data/lib/multiwoven/integrations/source/bigquery/client.rb +6 -0
  26. data/lib/multiwoven/integrations/source/bigquery/config/meta.json +1 -1
  27. data/lib/multiwoven/integrations/source/redshift/client.rb +5 -0
  28. data/lib/multiwoven/integrations/source/redshift/config/meta.json +1 -1
  29. data/lib/multiwoven/integrations/source/snowflake/client.rb +5 -0
  30. data/lib/multiwoven/integrations/source/snowflake/config/meta.json +1 -1
  31. data/lib/multiwoven/integrations.rb +6 -0
  32. data/multiwoven-integrations.gemspec +10 -6
  33. metadata +65 -8
@@ -0,0 +1,317 @@
1
+ {
2
+ "streams": [
3
+ {
4
+ "name": "Account",
5
+ "action": "create",
6
+ "json_schema": {
7
+ "type": "object",
8
+ "additionalProperties": true,
9
+ "properties": {
10
+ "Id": {
11
+ "type": "string"
12
+ },
13
+ "IsDeleted": {
14
+ "type": "boolean"
15
+ },
16
+ "MasterRecordId": {
17
+ "type": ["string", "null"]
18
+ },
19
+ "Name": {
20
+ "type": "string"
21
+ },
22
+ "Type": {
23
+ "type": ["string", "null"],
24
+ "enum": [
25
+ "Prospect",
26
+ "Customer - Direct",
27
+ "Customer - Channel",
28
+ "Channel Partner / Reseller",
29
+ "Installation Partner",
30
+ "Technology Partner",
31
+ "Other"
32
+ ]
33
+ },
34
+ "ParentId": {
35
+ "type": ["string", "null"]
36
+ },
37
+ "BillingStreet": {
38
+ "type": ["string", "null"]
39
+ },
40
+ "BillingCity": {
41
+ "type": ["string", "null"]
42
+ },
43
+ "BillingState": {
44
+ "type": ["string", "null"]
45
+ },
46
+ "BillingPostalCode": {
47
+ "type": ["string", "null"]
48
+ },
49
+ "BillingCountry": {
50
+ "type": ["string", "null"]
51
+ },
52
+ "BillingLatitude": {
53
+ "type": ["number", "null"]
54
+ },
55
+ "BillingLongitude": {
56
+ "type": ["number", "null"]
57
+ },
58
+ "BillingGeocodeAccuracy": {
59
+ "type": ["string", "null"],
60
+ "enum": [
61
+ "Address",
62
+ "NearAddress",
63
+ "Block",
64
+ "Street",
65
+ "ExtendedZip",
66
+ "Zip",
67
+ "Neighborhood",
68
+ "City",
69
+ "County",
70
+ "State",
71
+ "Unknown"
72
+ ]
73
+ },
74
+ "BillingAddress": {
75
+ "type": ["string", "null"],
76
+ "enum": [
77
+ "Address",
78
+ "NearAddress",
79
+ "Block",
80
+ "Street",
81
+ "ExtendedZip",
82
+ "Zip",
83
+ "Neighborhood",
84
+ "City",
85
+ "County",
86
+ "State",
87
+ "Unknown"
88
+ ]
89
+ },
90
+ "ShippingStreet": {
91
+ "type": ["string", "null"]
92
+ },
93
+ "ShippingCity": {
94
+ "type": ["string", "null"]
95
+ },
96
+ "ShippingState": {
97
+ "type": ["string", "null"]
98
+ },
99
+ "ShippingPostalCode": {
100
+ "type": ["string", "null"]
101
+ },
102
+ "ShippingCountry": {
103
+ "type": ["string", "null"]
104
+ },
105
+ "ShippingLatitude": {
106
+ "type": ["number", "null"]
107
+ },
108
+ "ShippingLongitude": {
109
+ "type": ["number", "null"]
110
+ },
111
+ "ShippingGeocodeAccuracy": {
112
+ "type": ["string", "null"]
113
+ },
114
+ "ShippingAddress": {
115
+ "type": ["string", "null"]
116
+ },
117
+ "Phone": {
118
+ "type": ["string", "null"]
119
+ },
120
+ "Fax": {
121
+ "type": ["string", "null"]
122
+ },
123
+ "AccountNumber": {
124
+ "type": ["string", "null"]
125
+ },
126
+ "Website": {
127
+ "type": ["string", "null"],
128
+ "format": "uri"
129
+ },
130
+ "PhotoUrl": {
131
+ "type": ["string", "null"],
132
+ "format": "uri"
133
+ },
134
+ "Sic": {
135
+ "type": ["string", "null"]
136
+ },
137
+ "Industry": {
138
+ "type": ["string", "null"],
139
+ "enum": [
140
+ "Agriculture",
141
+ "Apparel",
142
+ "Banking",
143
+ "Biotechnology",
144
+ "Chemicals",
145
+ "Communications",
146
+ "Construction",
147
+ "Consulting",
148
+ "Education",
149
+ "Electronics",
150
+ "Energy",
151
+ "Engineering",
152
+ "Entertainment",
153
+ "Environmental",
154
+ "Finance",
155
+ "Food & Beverage",
156
+ "Government",
157
+ "Healthcare",
158
+ "Hospitality",
159
+ "Insurance",
160
+ "Machinery",
161
+ "Manufacturing",
162
+ "Media",
163
+ "Not For Profit",
164
+ "Recreation",
165
+ "Retail",
166
+ "Shipping",
167
+ "Technology",
168
+ "Telecommunications",
169
+ "Transportation",
170
+ "Utilities",
171
+ "Other"
172
+ ]
173
+ },
174
+ "AnnualRevenue": {
175
+ "type": ["number", "null"]
176
+ },
177
+ "NumberOfEmployees": {
178
+ "type": ["integer", "null"]
179
+ },
180
+ "Ownership": {
181
+ "type": ["string", "null"],
182
+ "enum": ["Public", "Private", "Subsidiary", "Other"]
183
+ },
184
+ "TickerSymbol": {
185
+ "type": ["string", "null"]
186
+ },
187
+ "Description": {
188
+ "type": ["string", "null"]
189
+ },
190
+ "Rating": {
191
+ "type": ["string", "null"],
192
+ "enum": ["Hot", "Warm", "Cold"]
193
+ },
194
+ "Site": {
195
+ "type": ["string", "null"]
196
+ },
197
+ "OwnerId": {
198
+ "type": "string"
199
+ },
200
+ "CreatedDate": {
201
+ "type": "string",
202
+ "format": "date-time"
203
+ },
204
+ "CreatedById": {
205
+ "type": "string"
206
+ },
207
+ "LastModifiedDate": {
208
+ "type": "string",
209
+ "format": "date-time"
210
+ },
211
+ "LastModifiedById": {
212
+ "type": "string"
213
+ },
214
+ "SystemModstamp": {
215
+ "type": "string",
216
+ "format": "date-time"
217
+ },
218
+ "LastActivityDate": {
219
+ "type": ["string", "null"],
220
+ "format": "date"
221
+ },
222
+ "LastViewedDate": {
223
+ "type": ["string", "null"],
224
+ "format": "date-time"
225
+ },
226
+ "LastReferencedDate": {
227
+ "type": ["string", "null"],
228
+ "format": "date-time"
229
+ },
230
+ "Jigsaw": {
231
+ "type": ["string", "null"]
232
+ },
233
+ "JigsawCompanyId": {
234
+ "type": ["string", "null"]
235
+ },
236
+ "CleanStatus": {
237
+ "type": ["string", "null"],
238
+ "enum": [
239
+ "In Sync",
240
+ "Different",
241
+ "Reviewed",
242
+ "Not Found",
243
+ "Inactive",
244
+ "Not Compared",
245
+ "Select Match",
246
+ "Skipped"
247
+ ]
248
+ },
249
+ "AccountSource": {
250
+ "type": ["string", "null"],
251
+ "enum": [
252
+ "Web",
253
+ "Phone Inquiry",
254
+ "Partner Referral",
255
+ "Purchased List",
256
+ "Other"
257
+ ]
258
+ },
259
+ "DunsNumber": {
260
+ "type": ["string", "null"]
261
+ },
262
+ "Tradestyle": {
263
+ "type": ["string", "null"]
264
+ },
265
+ "NaicsCode": {
266
+ "type": ["string", "null"]
267
+ },
268
+ "NaicsDesc": {
269
+ "type": ["string", "null"]
270
+ },
271
+ "YearStarted": {
272
+ "type": ["string", "null"]
273
+ },
274
+ "SicDesc": {
275
+ "type": ["string", "null"]
276
+ },
277
+ "DandbCompanyId": {
278
+ "type": ["string", "null"]
279
+ },
280
+ "OperatingHoursId": {
281
+ "type": ["string", "null"]
282
+ },
283
+ "CustomerPriority__c": {
284
+ "type": ["string", "null"],
285
+ "enum": ["High", "Low", "Medium"]
286
+ },
287
+ "SLA__c": {
288
+ "type": ["string", "null"],
289
+ "enum": ["Gold", "Silver", "Platinum", "Bronze"]
290
+ },
291
+ "Active__c": {
292
+ "type": ["string", "null"],
293
+ "enum": ["Yes", "No"]
294
+ },
295
+ "NumberofLocations__c": {
296
+ "type": ["number", "null"]
297
+ },
298
+ "UpsellOpportunity__c": {
299
+ "type": ["string", "null"],
300
+ "enum": ["Yes", "No", "Maybe"]
301
+ },
302
+ "SLASerialNumber__c": {
303
+ "type": ["string", "null"]
304
+ },
305
+ "SLAExpirationDate__c": {
306
+ "type": ["string", "null"],
307
+ "format": "date"
308
+ }
309
+ }
310
+ },
311
+ "supported_sync_modes": ["full_refresh", "incremental"],
312
+ "source_defined_cursor": true,
313
+ "default_cursor_field": ["updated"],
314
+ "source_defined_primary_key": [["Id"]]
315
+ }
316
+ ]
317
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "data":
3
+ {
4
+ "name": "Salesforce CRM",
5
+ "connector_type": "destination",
6
+ "category": "CRM",
7
+ "documentation_url": "https://docs.mutliwoven.com",
8
+ "github_issue_label": "destination-salesforce-crm",
9
+ "icon": "salesforce.svg",
10
+ "license": "MIT",
11
+ "release_stage": "alpha",
12
+ "support_level": "community",
13
+ "tags": ["language:ruby", "multiwoven"]
14
+ }
15
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "documentation_url": "https://docs.multiwoven.com/integrations/destination/salesforce_crm",
3
+ "stream_type": "static",
4
+ "connection_specification": {
5
+ "$schema": "http://json-schema.org/draft-07/schema#",
6
+ "title": "Salesforce Destination Spec",
7
+ "type": "object",
8
+ "required": ["access_token", "refresh_token", "instance_url", "client_id", "client_secret"],
9
+ "properties": {
10
+ "access_token": {
11
+ "type": "string",
12
+ "title": "Access Token",
13
+ "order": 0
14
+ },
15
+ "refresh_token": {
16
+ "type": "string",
17
+ "title": "Refresh Token",
18
+ "order": 1
19
+ },
20
+ "instance_url": {
21
+ "type": "string",
22
+ "title": "Instance URL",
23
+ "order": 2
24
+ },
25
+ "client_id": {
26
+ "type": "string",
27
+ "title": "Client ID",
28
+ "order": 3
29
+ },
30
+ "client_secret": {
31
+ "type": "string",
32
+ "title": "Client Secret",
33
+ "order": 4
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven
4
+ module Integrations
5
+ module Destination
6
+ module Slack
7
+ include Multiwoven::Integrations::Core
8
+
9
+ class Client < DestinationConnector
10
+ attr_accessor :channel_id
11
+
12
+ def check_connection(connection_config)
13
+ configure_slack(connection_config[:api_token])
14
+ client = ::Slack::Web::Client.new
15
+ client.auth_test
16
+ success_status
17
+ rescue StandardError => e
18
+ failure_status(e)
19
+ end
20
+
21
+ def discover(_connection_config = nil)
22
+ catalog = build_catalog(load_catalog_streams)
23
+ catalog.to_multiwoven_message
24
+ rescue StandardError => e
25
+ handle_exception("SLACK:DISCOVER:EXCEPTION", "error", e)
26
+ end
27
+
28
+ def write(sync_config, records, action = "create")
29
+ # Currently as we only create a message for each record in slack, we are not using actions.
30
+ # This will be changed in future.
31
+
32
+ @action = sync_config.stream.action || action
33
+ connection_config = sync_config.destination.connection_specification.with_indifferent_access
34
+ configure_slack(connection_config[:api_token])
35
+ @client = ::Slack::Web::Client.new
36
+ @channel_id = connection_config[:channel_id]
37
+ process_records(records, sync_config.stream)
38
+ rescue StandardError => e
39
+ handle_exception("SLACK:WRITE:EXCEPTION", "error", e)
40
+ end
41
+
42
+ private
43
+
44
+ def configure_slack(api_token)
45
+ ::Slack.configure do |config|
46
+ config.token = api_token
47
+ end
48
+ end
49
+
50
+ def process_records(records, stream)
51
+ write_success = 0
52
+ write_failure = 0
53
+ records.each do |record_object|
54
+ process_record(stream, record_object.with_indifferent_access)
55
+ write_success += 1
56
+ rescue StandardError => e
57
+ write_failure += 1
58
+ handle_exception("SLACK:CRM:WRITE:EXCEPTION", "error", e)
59
+ end
60
+ tracking_message(write_success, write_failure)
61
+ end
62
+
63
+ def process_record(stream, record)
64
+ send_data_to_slack(stream[:name], record)
65
+ end
66
+
67
+ def send_data_to_slack(stream_name, record = {})
68
+ args = build_args(stream_name, record)
69
+ @client.send(stream_name, **args)
70
+ end
71
+
72
+ def build_args(stream_name, record)
73
+ case stream_name
74
+ when "chat_postMessage"
75
+ { channel: channel_id, text: slack_code_block(record[:data]) }
76
+ else
77
+ raise "Stream name not found: #{stream_name}"
78
+ end
79
+ end
80
+
81
+ def slack_code_block(data)
82
+ longest_key = data.keys.map(&:to_s).max_by(&:length).length
83
+ table_str = "```\n"
84
+ data.each do |key, value|
85
+ table_str += "#{key.to_s.ljust(longest_key)} : #{value}\n"
86
+ end
87
+ table_str += "```"
88
+
89
+ table_str
90
+ end
91
+
92
+ def success_status
93
+ ConnectionStatus.new(status: ConnectionStatusType["succeeded"]).to_multiwoven_message
94
+ end
95
+
96
+ def failure_status(error)
97
+ ConnectionStatus.new(status: ConnectionStatusType["failed"], message: error.message).to_multiwoven_message
98
+ end
99
+
100
+ def load_catalog_streams
101
+ catalog_json = read_json(CATALOG_SPEC_PATH)
102
+ catalog_json["streams"].map { |stream| build_stream(stream) }
103
+ end
104
+
105
+ def build_stream(stream)
106
+ Multiwoven::Integrations::Protocol::Stream.new(
107
+ name: stream["name"], json_schema: stream["json_schema"],
108
+ action: stream["action"]
109
+ )
110
+ end
111
+
112
+ def build_catalog(streams)
113
+ Multiwoven::Integrations::Protocol::Catalog.new(streams: streams)
114
+ end
115
+
116
+ def tracking_message(success, failure)
117
+ Multiwoven::Integrations::Protocol::TrackingMessage.new(
118
+ success: success, failed: failure
119
+ ).to_multiwoven_message
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,71 @@
1
+ {
2
+ "streams": [
3
+ {
4
+ "name": "chat_postMessage",
5
+ "action": "create",
6
+ "json_schema": {
7
+ "type": "object",
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "text": {
11
+ "type": ["string", "null"]
12
+ },
13
+ "attachments": {
14
+ "type": ["string", "null"]
15
+ },
16
+ "blocks": {
17
+ "type": ["array", "null"],
18
+ "items": {
19
+ "type": "string"
20
+ }
21
+ },
22
+ "as_user": {
23
+ "type": ["boolean", "null"]
24
+ },
25
+ "icon_emoji": {
26
+ "type": ["string", "null"]
27
+ },
28
+ "icon_url": {
29
+ "type": ["string", "null"]
30
+ },
31
+ "link_names": {
32
+ "type": ["boolean", "null"]
33
+ },
34
+ "metadata": {
35
+ "type": ["string", "null"]
36
+ },
37
+ "mrkdwn": {
38
+ "type": ["boolean", "null"]
39
+ },
40
+ "parse": {
41
+ "type": ["string", "null"]
42
+ },
43
+ "reply_broadcast": {
44
+ "type": ["boolean", "null"]
45
+ },
46
+ "thread_ts": {
47
+ "type": ["string", "null"]
48
+ },
49
+ "unfurl_links": {
50
+ "type": ["boolean", "null"]
51
+ },
52
+ "unfurl_media": {
53
+ "type": ["boolean", "null"]
54
+ },
55
+ "username": {
56
+ "type": ["string", "null"]
57
+ }
58
+ },
59
+ "oneOf": [
60
+ { "required": ["text"] },
61
+ { "required": ["attachments"] },
62
+ { "required": ["blocks"] }
63
+ ]
64
+ },
65
+ "supported_sync_modes": ["full_refresh", "incremental"],
66
+ "source_defined_cursor": true,
67
+ "default_cursor_field": ["updated"],
68
+ "source_defined_primary_key": [["Id"]]
69
+ }
70
+ ]
71
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "data": {
3
+ "name": "Slack",
4
+ "connector_type": "destination",
5
+ "category": "Team Collaboration",
6
+ "documentation_url": "https://docs.mutliwoven.com",
7
+ "github_issue_label": "destination-slack",
8
+ "icon": "slack.svg",
9
+ "license": "MIT",
10
+ "release_stage": "alpha",
11
+ "support_level": "community",
12
+ "tags": ["language:ruby", "multiwoven"]
13
+ }
14
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "documentation_url": "https://docs.multiwoven.com/integrations/destination/slack",
3
+ "stream_type": "static",
4
+ "connection_specification": {
5
+ "$schema": "http://json-schema.org/draft-07/schema#",
6
+ "title": "Slack Destination Spec",
7
+ "type": "object",
8
+ "required": ["api_token"],
9
+ "properties": {
10
+ "api_token": {
11
+ "type": "string",
12
+ "title": "API Token",
13
+ "order": 0
14
+ },
15
+ "channel_id": {
16
+ "type": "string",
17
+ "title": "Channel ID",
18
+ "order": 1
19
+ }
20
+ }
21
+ }
22
+ }
@@ -130,6 +130,8 @@ module Multiwoven
130
130
  end
131
131
 
132
132
  class SyncConfig < ProtocolModel
133
+ attr_accessor :offset, :limit
134
+
133
135
  attribute :source, Connector
134
136
  attribute :destination, Connector
135
137
  attribute :model, Model
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Multiwoven
4
4
  module Integrations
5
- VERSION = "0.1.1"
5
+ VERSION = "0.1.6"
6
6
 
7
7
  ENABLED_SOURCES = %w[
8
8
  Snowflake
@@ -12,6 +12,9 @@ module Multiwoven
12
12
 
13
13
  ENABLED_DESTINATIONS = %w[
14
14
  Klaviyo
15
+ SalesforceCrm
16
+ FacebookCustomAudience
17
+ Slack
15
18
  ].freeze
16
19
  end
17
20
  end
@@ -7,6 +7,7 @@ module Multiwoven::Integrations::Source
7
7
  include Multiwoven::Integrations::Core
8
8
  class Client < SourceConnector
9
9
  def check_connection(connection_config)
10
+ connection_config = connection_config.with_indifferent_access
10
11
  bigquery = create_connection(connection_config)
11
12
  bigquery.datasets
12
13
  ConnectionStatus.new(status: ConnectionStatusType["succeeded"]).to_multiwoven_message
@@ -15,6 +16,7 @@ module Multiwoven::Integrations::Source
15
16
  end
16
17
 
17
18
  def discover(connection_config)
19
+ connection_config = connection_config.with_indifferent_access
18
20
  bigquery = create_connection(connection_config)
19
21
  target_dataset_id = connection_config["dataset_id"]
20
22
  records = bigquery.datasets.flat_map do |dataset|
@@ -43,7 +45,11 @@ module Multiwoven::Integrations::Source
43
45
 
44
46
  def read(sync_config)
45
47
  connection_config = sync_config.source.connection_specification
48
+ connection_config = connection_config.with_indifferent_access
46
49
  query = sync_config.model.query
50
+
51
+ query = batched_query(query, sync_config.limit, sync_config.offset) unless sync_config.limit.nil? && sync_config.offset.nil?
52
+
47
53
  bigquery = create_connection(connection_config)
48
54
  records = []
49
55
  results = bigquery.query query
@@ -3,7 +3,7 @@
3
3
  {
4
4
  "name": "BigQuery",
5
5
  "connector_type": "source",
6
- "connector_subtype": "database",
6
+ "category": "Data Warehouse",
7
7
  "documentation_url": "https://docs.mutliwoven.com",
8
8
  "github_issue_label": "source-bigquery",
9
9
  "icon": "bigquery.svg",