multiwoven-integrations 0.18.5 → 0.19.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: 6f5f6890969a89be17fe50cb2fd9ff8f863b185de80b6153837ef8a031edf293
4
- data.tar.gz: f76b6b9d309d6336ea4650b8b27e9752a646a78d1a501d74537ffafae7752bc6
3
+ metadata.gz: dbb3e326a630a72bdfc3bdd812dee5775ec035f4cb4367485c6c3f07ca95530b
4
+ data.tar.gz: 7cf87b1c5e54f38834c612f84bc5bd5afea9b50a25fe9e301a8e4f6ad9c3b80d
5
5
  SHA512:
6
- metadata.gz: b3eb67d238ea710d230a6a41404046864eab190dadf4341035441196fc7637c1c70ebe390806808a09d4ccef95cfd53e90e6e9bb33e7cc8f778b481c8a34ce83
7
- data.tar.gz: e30a2fa6adb0293bd07e467b475df793a38bf271e9b48d41c7ff3d41a9f1ba2d9b791acb9f51582c7f3fbfe123e8a8592d9758bf7a384cc309762c94e97f8dc9
6
+ metadata.gz: 4ed79bc81b1022578f20cfe10e883b120d834a8475d885383939256f8eefcb9f8acb72de4da5cefbc0c0aa7f5aeb1738c0aaa6cf65d0551ad5a25df28976f5c9
7
+ data.tar.gz: b6b3ed98a1a05ff42b290b81f2c5a309fc2baf97957bc40fb543821ce32ddfae1a75cd8daf151df8a451cecc7fa3ba75a474c4ae707fec5fb6d74c366bb209bd
@@ -46,6 +46,8 @@ module Multiwoven
46
46
  "workbook/worksheets"
47
47
  MS_EXCEL_SHEET_RANGE_API = "https://graph.microsoft.com/v1.0/drives/%<drive_id>s/items/%<item_id>s/"\
48
48
  "workbook/worksheets/%<sheet_name>s/range(address='A1:Z1')/usedRange?$select=values"
49
+ MS_DYNAMICS_WHOAMI_API = "https://%<instance_url>s.crm.dynamics.com/api/data/v%<api_version>s/WhoAmI"
50
+ MS_DYNAMICS_REST_API = "https://%<instance_url>s.crm.dynamics.com/api/data/v%<api_version>s/%<entity>s"
49
51
 
50
52
  DATABRICKS_HEALTH_URL = "https://%<databricks_host>s/api/2.0/serving-endpoints/%<endpoint_name>s"
51
53
  DATABRICKS_SERVING_URL = "https://%<databricks_host>s/serving-endpoints/%<endpoint_name>s/invocations"
@@ -39,6 +39,8 @@ module Multiwoven
39
39
  case type
40
40
  when "NUMBER"
41
41
  "integer"
42
+ when "vector"
43
+ "vector"
42
44
  else
43
45
  "string" # Default type
44
46
  end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven::Integrations::Destination
4
+ module MicrosoftDynamics
5
+ include Multiwoven::Integrations::Core
6
+ API_VERSION = "9.2"
7
+ class Client < DestinationConnector
8
+ def check_connection(connection_config)
9
+ connection_config = connection_config.with_indifferent_access
10
+ initialize_client(connection_config)
11
+ token_response = create_access_token
12
+ uri = URI.parse(format(MS_DYNAMICS_WHOAMI_API, instance_url: @instance_url, api_version: API_VERSION))
13
+ http = Net::HTTP.new(uri.host, uri.port)
14
+ http.use_ssl = (uri.scheme == "https")
15
+ request = Net::HTTP::Get.new(uri)
16
+ auth_headers(token_response["access_token"]).each { |key, value| request[key] = value }
17
+ response = http.request(request)
18
+ response_body = JSON.parse(response.body)
19
+
20
+ if success?(response) && response_body.key?("UserId")
21
+ success_status
22
+ else
23
+ failure_status(nil)
24
+ end
25
+ rescue StandardError => e
26
+ handle_exception(e, {
27
+ context: "MICROSOFT:DYNAMICS:CHECK_CONNECTION:EXCEPTION",
28
+ type: "error"
29
+ })
30
+ failure_status(e)
31
+ end
32
+
33
+ def discover(_connection_config = nil)
34
+ catalog_json = read_json(CATALOG_SPEC_PATH)
35
+ catalog = build_catalog(catalog_json)
36
+ catalog.to_multiwoven_message
37
+ rescue StandardError => e
38
+ handle_exception(e, {
39
+ context: "MICROSOFT:DYNAMICS:DISCOVER:EXCEPTION",
40
+ type: "error"
41
+ })
42
+ end
43
+
44
+ def write(sync_config, records, _action = "upsert")
45
+ @sync_config = sync_config
46
+ stream = @sync_config.stream
47
+ connection_config = @sync_config.destination.connection_specification.with_indifferent_access
48
+ create_connection(connection_config)
49
+ build_url(stream)
50
+ process_records(records, stream)
51
+ rescue StandardError => e
52
+ handle_exception(e, {
53
+ context: "MICROSOFT:DYNAMICS:WRITE:EXCEPTION",
54
+ type: "error",
55
+ sync_id: @sync_config.sync_id,
56
+ sync_run_id: @sync_config.sync_run_id
57
+ })
58
+ end
59
+
60
+ private
61
+
62
+ def create_access_token
63
+ uri = URI.parse("https://login.microsoftonline.com/#{@tenant_id}/oauth2/v2.0/token")
64
+
65
+ payload = {
66
+ client_id: @client_id,
67
+ client_secret: @client_secret,
68
+ scope: "https://#{@instance_url}.crm.dynamics.com/.default",
69
+ grant_type: "client_credentials"
70
+ }
71
+
72
+ response = Net::HTTP.post_form(uri, payload)
73
+ JSON.parse(response.body)
74
+ end
75
+
76
+ def get_access_token(cache)
77
+ cache_key = "dynamics_#{@instance_url}_#{@tenant_id}_#{@client_id}"
78
+ cached_token = cache.read(cache_key)
79
+ if cached_token
80
+ @access_token = cached_token
81
+ else
82
+ new_token = create_access_token
83
+ # max expiration is 3 minutes. No way to make it higher
84
+ cache.write(cache_key, new_token["access_token"], expires_in: 180)
85
+ @access_token = new_token["access_token"]
86
+ end
87
+ end
88
+
89
+ def create_connection(connection_config)
90
+ cache = defined?(Rails) && Rails.respond_to?(:cache) ? Rails.cache : ActiveSupport::Cache::MemoryStore.new
91
+ initialize_client(connection_config)
92
+ get_access_token(cache)
93
+ end
94
+
95
+ def initialize_client(connection_config)
96
+ @tenant_id = connection_config[:tenant_id]
97
+ @client_id = connection_config[:application_id]
98
+ @instance_url = connection_config[:instance_url]
99
+ @client_secret = connection_config[:client_secret]
100
+ end
101
+
102
+ def process_records(records, stream)
103
+ write_success = 0
104
+ write_failure = 0
105
+ properties = stream.json_schema[:properties]
106
+ log_message_array = []
107
+
108
+ records.each do |record_object|
109
+ record = extract_data(record_object, properties)
110
+ response = send_data_to_dynamics(record)
111
+ response_code = response.code.to_i
112
+ if response_code >= 200 && response_code < 300
113
+ write_success += 1
114
+ log_message_array << log_request_response("info", record, response["location"])
115
+ else
116
+ write_failure += 1
117
+ log_message_array << log_request_response("error", record, response.body)
118
+ end
119
+ rescue StandardError => e
120
+ # TODO: add sync_id and sync run id to the logs
121
+ handle_exception(e, {
122
+ context: "MICROSOFT:DYNAMICS:WRITE:EXCEPTION",
123
+ type: "error",
124
+ sync_id: @sync_config.sync_id,
125
+ sync_run_id: @sync_config.sync_run_id
126
+ })
127
+ write_failure += 1
128
+ log_message_array << log_request_response("error", record, e.message)
129
+ end
130
+ tracking_message(write_success, write_failure, log_message_array)
131
+ end
132
+
133
+ def build_url(stream)
134
+ @destination_url = format(MS_DYNAMICS_REST_API, instance_url: @instance_url, api_version: API_VERSION, entity: stream.name)
135
+ end
136
+
137
+ def send_data_to_dynamics(payload)
138
+ uri = URI.parse(@destination_url)
139
+
140
+ http = Net::HTTP.new(uri.host, uri.port)
141
+ http.use_ssl = (uri.scheme == "https")
142
+
143
+ request = Net::HTTP::Post.new(uri)
144
+ auth_headers(@access_token).each { |key, value| request[key] = value }
145
+ request.body = payload.to_json
146
+ http.request(request)
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,161 @@
1
+ {
2
+ "request_rate_limit": 40000,
3
+ "request_rate_limit_unit": "day",
4
+ "request_rate_concurrency": 10,
5
+ "streams": [
6
+ {
7
+ "name": "accounts",
8
+ "action": "create",
9
+ "json_schema": {
10
+ "type": "object",
11
+ "additionalProperties": true,
12
+ "required": ["name"],
13
+ "properties": {
14
+ "name": {
15
+ "type": "string"
16
+ },
17
+ "account_number": {
18
+ "type": "string"
19
+ },
20
+ "telephone1": {
21
+ "type": "string"
22
+ },
23
+ "emailaddress1": {
24
+ "type": "string",
25
+ "format": "email"
26
+ },
27
+ "websiteurl": {
28
+ "type": "string",
29
+ "format": "uri"
30
+ },
31
+ "address1_line1": {
32
+ "type": "string"
33
+ },
34
+ "address1_city": {
35
+ "type": "string"
36
+ },
37
+ "address1_stateorprovince": {
38
+ "type": "string"
39
+ },
40
+ "address1_postalcode": {
41
+ "type": "string"
42
+ },
43
+ "industrycode": {
44
+ "type": "integer"
45
+ },
46
+ "revenue": {
47
+ "type": "number",
48
+ "format": "float"
49
+ },
50
+ "numberofemployees": {
51
+ "type": "integer"
52
+ }
53
+ }
54
+ },
55
+ "supported_sync_modes": ["incremental"],
56
+ "source_defined_cursor": false,
57
+ "source_defined_primary_key": ["account_number"]
58
+ },
59
+ {
60
+ "name": "contacts",
61
+ "action": "create",
62
+ "json_schema": {
63
+ "type": "object",
64
+ "additionalProperties": true,
65
+ "required": ["emailaddress1", "firstname", "lastname"],
66
+ "properties": {
67
+ "firstname": {
68
+ "type": "string"
69
+ },
70
+ "lastname": {
71
+ "type": "string"
72
+ },
73
+ "emailaddress1": {
74
+ "type": "string",
75
+ "format": "email"
76
+ },
77
+ "mobilephone": {
78
+ "type": "string"
79
+ },
80
+ "telephone1": {
81
+ "type": "string"
82
+ },
83
+ "address1_line1": {
84
+ "type": "string"
85
+ },
86
+ "address1_city": {
87
+ "type": "string"
88
+ },
89
+ "address1_stateorprovince": {
90
+ "type": "string"
91
+ },
92
+ "address1_postalcode": {
93
+ "type": "string"
94
+ },
95
+ "jobtitle": {
96
+ "type": "string"
97
+ },
98
+ "parentcustomerid": {
99
+ "type": "string",
100
+ "description": "ID of the associated Account"
101
+ }
102
+ }
103
+ },
104
+ "supported_sync_modes": ["incremental"],
105
+ "source_defined_cursor": false,
106
+ "source_defined_primary_key": ["emailaddress1"]
107
+ },
108
+ {
109
+ "name": "opportunities",
110
+ "action": "create",
111
+ "json_schema": {
112
+ "type": "object",
113
+ "additionalProperties": true,
114
+ "required": ["name", "customerid", "estimatedvalue"],
115
+ "properties": {
116
+ "name": {
117
+ "type": "string"
118
+ },
119
+ "customerid": {
120
+ "type": "string",
121
+ "description": "ID of the associated Account or Contact"
122
+ },
123
+ "estimatedvalue": {
124
+ "type": "number",
125
+ "format": "float"
126
+ },
127
+ "description": {
128
+ "type": "string"
129
+ },
130
+ "closeprobability": {
131
+ "type": "integer",
132
+ "minimum": 0,
133
+ "maximum": 100
134
+ },
135
+ "estimatedclosedate": {
136
+ "type": "string",
137
+ "format": "date"
138
+ },
139
+ "actualclosedate": {
140
+ "type": "string",
141
+ "format": "date"
142
+ },
143
+ "opportunityratingcode": {
144
+ "type": "string",
145
+ "enum": ["Hot", "Warm", "Cold"]
146
+ },
147
+ "stageid": {
148
+ "type": "string"
149
+ },
150
+ "ownerid": {
151
+ "type": "string",
152
+ "description": "ID of the owner (user or team)"
153
+ }
154
+ }
155
+ },
156
+ "supported_sync_modes": ["incremental"],
157
+ "source_defined_cursor": false,
158
+ "source_defined_primary_key": ["customerid"]
159
+ }
160
+ ]
161
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "data": {
3
+ "name": "MicrosoftDynamics",
4
+ "title": "Microsoft Dynamics",
5
+ "connector_type": "destination",
6
+ "category": "CRM",
7
+ "documentation_url": "https://docs.mutliwoven.com",
8
+ "github_issue_label": "destination-microsoft-dynamics",
9
+ "icon": "icon.svg",
10
+ "license": "MIT",
11
+ "release_stage": "alpha",
12
+ "support_level": "community",
13
+ "tags": ["language:ruby", "multiwoven"]
14
+ }
15
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "documentation_url": "https://docs.multiwoven.com/integrations/destination/microsoft_dynamics",
3
+ "stream_type": "dynamic",
4
+ "connector_query_type": "raw_sql",
5
+ "connection_specification": {
6
+ "$schema": "http://json-schema.org/draft-07/schema#",
7
+ "title": "Microsoft Dynamics",
8
+ "type": "object",
9
+ "required": ["instance_url", "tenant_id", "application_id", "client_secret"],
10
+ "properties": {
11
+ "instance_url": {
12
+ "type": "string",
13
+ "title": "Organization Name",
14
+ "order": 0
15
+ },
16
+ "tenant_id": {
17
+ "type": "string",
18
+ "multiwoven_secret": true,
19
+ "title": "Tenant ID",
20
+ "order": 1
21
+ },
22
+ "application_id": {
23
+ "type": "string",
24
+ "title": "Application ID",
25
+ "order": 2
26
+ },
27
+ "client_secret": {
28
+ "type": "string",
29
+ "multiwoven_secret": true,
30
+ "title": "Client Secret",
31
+ "order": 3
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,2 @@
1
+ <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
2
+ <svg fill="#000000" width="800px" height="800px" viewBox="0 0 24 24" role="img" xmlns="http://www.w3.org/2000/svg"><title>Dynamics 365 icon</title><path d="M4.59 7.41l4.94 3.54L4.59 24zm0-7.41v6.36l9.53 5.29 4.59-3.52zm0 24l14.82-8.47v-6.7Z"/></svg>
@@ -20,7 +20,10 @@ module Multiwoven::Integrations::Destination
20
20
 
21
21
  def discover(connection_config)
22
22
  connection_config = connection_config.with_indifferent_access
23
- query = "SELECT table_name, column_name, data_type, is_nullable
23
+ query = "SELECT table_name, column_name,
24
+ CASE WHEN data_type = 'USER-DEFINED' THEN udt_name ELSE data_type END
25
+ AS data_type,
26
+ is_nullable
24
27
  FROM information_schema.columns
25
28
  WHERE table_schema = '#{connection_config[:schema]}' AND table_catalog = '#{connection_config[:database]}'
26
29
  ORDER BY table_name, ordinal_position;"
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Multiwoven
4
4
  module Integrations
5
- VERSION = "0.18.5"
5
+ VERSION = "0.19.1"
6
6
 
7
7
  ENABLED_SOURCES = %w[
8
8
  Snowflake
@@ -47,6 +47,7 @@ module Multiwoven
47
47
  Mailchimp
48
48
  AISDataStore
49
49
  AmazonS3
50
+ MicrosoftDynamics
50
51
  ].freeze
51
52
  end
52
53
  end
@@ -99,6 +99,7 @@ require_relative "integrations/destination/microsoft_sql/client"
99
99
  require_relative "integrations/destination/mailchimp/client"
100
100
  require_relative "integrations/destination/ais_data_store/client"
101
101
  require_relative "integrations/destination/amazon_s3/client"
102
+ require_relative "integrations/destination/microsoft_dynamics/client"
102
103
 
103
104
  module Multiwoven
104
105
  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.18.5
4
+ version: 0.19.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: 2025-01-22 00:00:00.000000000 Z
11
+ date: 2025-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -644,6 +644,11 @@ files:
644
644
  - lib/multiwoven/integrations/destination/maria_db/config/meta.json
645
645
  - lib/multiwoven/integrations/destination/maria_db/config/spec.json
646
646
  - lib/multiwoven/integrations/destination/maria_db/icon.svg
647
+ - lib/multiwoven/integrations/destination/microsoft_dynamics/client.rb
648
+ - lib/multiwoven/integrations/destination/microsoft_dynamics/config/catalog.json
649
+ - lib/multiwoven/integrations/destination/microsoft_dynamics/config/meta.json
650
+ - lib/multiwoven/integrations/destination/microsoft_dynamics/config/spec.json
651
+ - lib/multiwoven/integrations/destination/microsoft_dynamics/icon.svg
647
652
  - lib/multiwoven/integrations/destination/microsoft_excel/client.rb
648
653
  - lib/multiwoven/integrations/destination/microsoft_excel/config/catalog.json
649
654
  - lib/multiwoven/integrations/destination/microsoft_excel/config/meta.json