outhad-integrations 0.32.0

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 (275) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +43 -0
  4. data/.ruby-version +1 -0
  5. data/.vscode/settings.json +5 -0
  6. data/README.md +76 -0
  7. data/Rakefile +12 -0
  8. data/lib/outhad/integrations/config.rb +14 -0
  9. data/lib/outhad/integrations/core/base_connector.rb +79 -0
  10. data/lib/outhad/integrations/core/constants.rb +103 -0
  11. data/lib/outhad/integrations/core/destination_connector.rb +20 -0
  12. data/lib/outhad/integrations/core/fullrefresher.rb +19 -0
  13. data/lib/outhad/integrations/core/http_client.rb +17 -0
  14. data/lib/outhad/integrations/core/http_helper.rb +36 -0
  15. data/lib/outhad/integrations/core/query_builder.rb +33 -0
  16. data/lib/outhad/integrations/core/rate_limiter.rb +19 -0
  17. data/lib/outhad/integrations/core/source_connector.rb +66 -0
  18. data/lib/outhad/integrations/core/streaming_http_client.rb +21 -0
  19. data/lib/outhad/integrations/core/unstructured_source_connector.rb +52 -0
  20. data/lib/outhad/integrations/core/utils.rb +123 -0
  21. data/lib/outhad/integrations/core/vector_source_connector.rb +14 -0
  22. data/lib/outhad/integrations/destination/airtable/client.rb +157 -0
  23. data/lib/outhad/integrations/destination/airtable/config/catalog.json +6 -0
  24. data/lib/outhad/integrations/destination/airtable/config/meta.json +15 -0
  25. data/lib/outhad/integrations/destination/airtable/config/spec.json +23 -0
  26. data/lib/outhad/integrations/destination/airtable/icon.svg +6 -0
  27. data/lib/outhad/integrations/destination/airtable/schema_helper.rb +141 -0
  28. data/lib/outhad/integrations/destination/ais_data_store/client.rb +130 -0
  29. data/lib/outhad/integrations/destination/ais_data_store/config/meta.json +15 -0
  30. data/lib/outhad/integrations/destination/ais_data_store/config/spec.json +68 -0
  31. data/lib/outhad/integrations/destination/ais_data_store/icon.svg +4 -0
  32. data/lib/outhad/integrations/destination/amazon_s3/client.rb +92 -0
  33. data/lib/outhad/integrations/destination/amazon_s3/config/catalog.json +16 -0
  34. data/lib/outhad/integrations/destination/amazon_s3/config/meta.json +15 -0
  35. data/lib/outhad/integrations/destination/amazon_s3/config/spec.json +56 -0
  36. data/lib/outhad/integrations/destination/amazon_s3/icon.svg +34 -0
  37. data/lib/outhad/integrations/destination/databricks_lakehouse/client.rb +147 -0
  38. data/lib/outhad/integrations/destination/databricks_lakehouse/config/meta.json +15 -0
  39. data/lib/outhad/integrations/destination/databricks_lakehouse/config/spec.json +44 -0
  40. data/lib/outhad/integrations/destination/databricks_lakehouse/icon.svg +65 -0
  41. data/lib/outhad/integrations/destination/facebook_custom_audience/client.rb +125 -0
  42. data/lib/outhad/integrations/destination/facebook_custom_audience/config/catalog.json +42 -0
  43. data/lib/outhad/integrations/destination/facebook_custom_audience/config/meta.json +15 -0
  44. data/lib/outhad/integrations/destination/facebook_custom_audience/config/spec.json +28 -0
  45. data/lib/outhad/integrations/destination/facebook_custom_audience/icon.svg +23 -0
  46. data/lib/outhad/integrations/destination/google_sheets/client.rb +240 -0
  47. data/lib/outhad/integrations/destination/google_sheets/config/catalog.json +6 -0
  48. data/lib/outhad/integrations/destination/google_sheets/config/meta.json +15 -0
  49. data/lib/outhad/integrations/destination/google_sheets/config/spec.json +75 -0
  50. data/lib/outhad/integrations/destination/google_sheets/icon.svg +1 -0
  51. data/lib/outhad/integrations/destination/http/client.rb +106 -0
  52. data/lib/outhad/integrations/destination/http/config/catalog.json +16 -0
  53. data/lib/outhad/integrations/destination/http/config/meta.json +15 -0
  54. data/lib/outhad/integrations/destination/http/config/spec.json +24 -0
  55. data/lib/outhad/integrations/destination/http/icon.svg +9 -0
  56. data/lib/outhad/integrations/destination/hubspot/client.rb +122 -0
  57. data/lib/outhad/integrations/destination/hubspot/config/catalog.json +351 -0
  58. data/lib/outhad/integrations/destination/hubspot/config/meta.json +15 -0
  59. data/lib/outhad/integrations/destination/hubspot/config/spec.json +18 -0
  60. data/lib/outhad/integrations/destination/hubspot/icon.svg +5 -0
  61. data/lib/outhad/integrations/destination/iterable/client.rb +111 -0
  62. data/lib/outhad/integrations/destination/iterable/config/catalog.json +47 -0
  63. data/lib/outhad/integrations/destination/iterable/config/meta.json +15 -0
  64. data/lib/outhad/integrations/destination/iterable/config/spec.json +19 -0
  65. data/lib/outhad/integrations/destination/iterable/icon.svg +71 -0
  66. data/lib/outhad/integrations/destination/klaviyo/client.rb +119 -0
  67. data/lib/outhad/integrations/destination/klaviyo/config/catalog.json +103 -0
  68. data/lib/outhad/integrations/destination/klaviyo/config/meta.json +15 -0
  69. data/lib/outhad/integrations/destination/klaviyo/config/spec.json +24 -0
  70. data/lib/outhad/integrations/destination/klaviyo/icon.svg +6 -0
  71. data/lib/outhad/integrations/destination/mailchimp/client.rb +141 -0
  72. data/lib/outhad/integrations/destination/mailchimp/config/catalog.json +142 -0
  73. data/lib/outhad/integrations/destination/mailchimp/config/meta.json +15 -0
  74. data/lib/outhad/integrations/destination/mailchimp/config/spec.json +28 -0
  75. data/lib/outhad/integrations/destination/mailchimp/icon.svg +4 -0
  76. data/lib/outhad/integrations/destination/maria_db/client.rb +114 -0
  77. data/lib/outhad/integrations/destination/maria_db/config/meta.json +15 -0
  78. data/lib/outhad/integrations/destination/maria_db/config/spec.json +48 -0
  79. data/lib/outhad/integrations/destination/maria_db/icon.svg +15 -0
  80. data/lib/outhad/integrations/destination/microsoft_dynamics/client.rb +150 -0
  81. data/lib/outhad/integrations/destination/microsoft_dynamics/config/catalog.json +161 -0
  82. data/lib/outhad/integrations/destination/microsoft_dynamics/config/meta.json +15 -0
  83. data/lib/outhad/integrations/destination/microsoft_dynamics/config/spec.json +35 -0
  84. data/lib/outhad/integrations/destination/microsoft_dynamics/icon.svg +2 -0
  85. data/lib/outhad/integrations/destination/microsoft_excel/client.rb +198 -0
  86. data/lib/outhad/integrations/destination/microsoft_excel/config/catalog.json +7 -0
  87. data/lib/outhad/integrations/destination/microsoft_excel/config/meta.json +15 -0
  88. data/lib/outhad/integrations/destination/microsoft_excel/config/spec.json +19 -0
  89. data/lib/outhad/integrations/destination/microsoft_excel/icon.svg +18 -0
  90. data/lib/outhad/integrations/destination/microsoft_sql/client.rb +137 -0
  91. data/lib/outhad/integrations/destination/microsoft_sql/config/meta.json +15 -0
  92. data/lib/outhad/integrations/destination/microsoft_sql/config/spec.json +68 -0
  93. data/lib/outhad/integrations/destination/microsoft_sql/icon.svg +22 -0
  94. data/lib/outhad/integrations/destination/odoo/client.rb +109 -0
  95. data/lib/outhad/integrations/destination/odoo/config/meta.json +15 -0
  96. data/lib/outhad/integrations/destination/odoo/config/spec.json +39 -0
  97. data/lib/outhad/integrations/destination/odoo/icon.svg +21 -0
  98. data/lib/outhad/integrations/destination/oracle_db/client.rb +112 -0
  99. data/lib/outhad/integrations/destination/oracle_db/config/meta.json +15 -0
  100. data/lib/outhad/integrations/destination/oracle_db/config/spec.json +47 -0
  101. data/lib/outhad/integrations/destination/oracle_db/icon.svg +4 -0
  102. data/lib/outhad/integrations/destination/pinecone_db/client.rb +154 -0
  103. data/lib/outhad/integrations/destination/pinecone_db/config/meta.json +15 -0
  104. data/lib/outhad/integrations/destination/pinecone_db/config/spec.json +32 -0
  105. data/lib/outhad/integrations/destination/pinecone_db/icon.svg +1 -0
  106. data/lib/outhad/integrations/destination/postgresql/client.rb +130 -0
  107. data/lib/outhad/integrations/destination/postgresql/config/meta.json +15 -0
  108. data/lib/outhad/integrations/destination/postgresql/config/spec.json +68 -0
  109. data/lib/outhad/integrations/destination/postgresql/icon.svg +20 -0
  110. data/lib/outhad/integrations/destination/qdrant/client.rb +184 -0
  111. data/lib/outhad/integrations/destination/qdrant/config/meta.json +15 -0
  112. data/lib/outhad/integrations/destination/qdrant/config/spec.json +23 -0
  113. data/lib/outhad/integrations/destination/qdrant/icon.svg +1 -0
  114. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/client.rb +136 -0
  115. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/catalog.json +6 -0
  116. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/meta.json +16 -0
  117. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/spec.json +52 -0
  118. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/icon.svg +16 -0
  119. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/schema_helper.rb +132 -0
  120. data/lib/outhad/integrations/destination/salesforce_crm/client.rb +114 -0
  121. data/lib/outhad/integrations/destination/salesforce_crm/config/catalog.json +320 -0
  122. data/lib/outhad/integrations/destination/salesforce_crm/config/meta.json +15 -0
  123. data/lib/outhad/integrations/destination/salesforce_crm/config/spec.json +46 -0
  124. data/lib/outhad/integrations/destination/salesforce_crm/icon.svg +16 -0
  125. data/lib/outhad/integrations/destination/sftp/client.rb +186 -0
  126. data/lib/outhad/integrations/destination/sftp/config/catalog.json +16 -0
  127. data/lib/outhad/integrations/destination/sftp/config/meta.json +16 -0
  128. data/lib/outhad/integrations/destination/sftp/config/spec.json +73 -0
  129. data/lib/outhad/integrations/destination/sftp/icon.svg +1 -0
  130. data/lib/outhad/integrations/destination/slack/client.rb +125 -0
  131. data/lib/outhad/integrations/destination/slack/config/catalog.json +22 -0
  132. data/lib/outhad/integrations/destination/slack/config/meta.json +15 -0
  133. data/lib/outhad/integrations/destination/slack/config/spec.json +23 -0
  134. data/lib/outhad/integrations/destination/slack/icon.svg +26 -0
  135. data/lib/outhad/integrations/destination/stripe/client.rb +94 -0
  136. data/lib/outhad/integrations/destination/stripe/config/catalog.json +128 -0
  137. data/lib/outhad/integrations/destination/stripe/config/meta.json +15 -0
  138. data/lib/outhad/integrations/destination/stripe/config/spec.json +18 -0
  139. data/lib/outhad/integrations/destination/stripe/icon.svg +10 -0
  140. data/lib/outhad/integrations/destination/zendesk/client.rb +132 -0
  141. data/lib/outhad/integrations/destination/zendesk/config/catalog.json +110 -0
  142. data/lib/outhad/integrations/destination/zendesk/config/meta.json +18 -0
  143. data/lib/outhad/integrations/destination/zendesk/config/spec.json +32 -0
  144. data/lib/outhad/integrations/destination/zendesk/icon.svg +63 -0
  145. data/lib/outhad/integrations/protocol/protocol.json +189 -0
  146. data/lib/outhad/integrations/protocol/protocol.rb +228 -0
  147. data/lib/outhad/integrations/rollout.rb +66 -0
  148. data/lib/outhad/integrations/service.rb +55 -0
  149. data/lib/outhad/integrations/source/amazon_s3/client.rb +235 -0
  150. data/lib/outhad/integrations/source/amazon_s3/config/meta.json +16 -0
  151. data/lib/outhad/integrations/source/amazon_s3/config/spec.json +119 -0
  152. data/lib/outhad/integrations/source/amazon_s3/icon.svg +34 -0
  153. data/lib/outhad/integrations/source/anthropic/client.rb +135 -0
  154. data/lib/outhad/integrations/source/anthropic/config/catalog.json +6 -0
  155. data/lib/outhad/integrations/source/anthropic/config/meta.json +16 -0
  156. data/lib/outhad/integrations/source/anthropic/config/spec.json +56 -0
  157. data/lib/outhad/integrations/source/anthropic/icon.svg +1 -0
  158. data/lib/outhad/integrations/source/aws_athena/client.rb +109 -0
  159. data/lib/outhad/integrations/source/aws_athena/config/meta.json +16 -0
  160. data/lib/outhad/integrations/source/aws_athena/config/spec.json +63 -0
  161. data/lib/outhad/integrations/source/aws_athena/icon.svg +22 -0
  162. data/lib/outhad/integrations/source/aws_bedrock_model/client.rb +91 -0
  163. data/lib/outhad/integrations/source/aws_bedrock_model/config/catalog.json +6 -0
  164. data/lib/outhad/integrations/source/aws_bedrock_model/config/meta.json +16 -0
  165. data/lib/outhad/integrations/source/aws_bedrock_model/config/spec.json +58 -0
  166. data/lib/outhad/integrations/source/aws_bedrock_model/icon.svg +1 -0
  167. data/lib/outhad/integrations/source/aws_sagemaker_model/client.rb +79 -0
  168. data/lib/outhad/integrations/source/aws_sagemaker_model/config/catalog.json +6 -0
  169. data/lib/outhad/integrations/source/aws_sagemaker_model/config/meta.json +16 -0
  170. data/lib/outhad/integrations/source/aws_sagemaker_model/config/spec.json +52 -0
  171. data/lib/outhad/integrations/source/aws_sagemaker_model/icon.svg +7 -0
  172. data/lib/outhad/integrations/source/bigquery/client.rb +98 -0
  173. data/lib/outhad/integrations/source/bigquery/config/meta.json +16 -0
  174. data/lib/outhad/integrations/source/bigquery/config/spec.json +83 -0
  175. data/lib/outhad/integrations/source/bigquery/icon.svg +1 -0
  176. data/lib/outhad/integrations/source/clickhouse/client.rb +102 -0
  177. data/lib/outhad/integrations/source/clickhouse/config/meta.json +16 -0
  178. data/lib/outhad/integrations/source/clickhouse/config/spec.json +42 -0
  179. data/lib/outhad/integrations/source/clickhouse/icon.svg +25 -0
  180. data/lib/outhad/integrations/source/databricks/client.rb +98 -0
  181. data/lib/outhad/integrations/source/databricks/config/meta.json +17 -0
  182. data/lib/outhad/integrations/source/databricks/config/spec.json +56 -0
  183. data/lib/outhad/integrations/source/databricks/icon.svg +19 -0
  184. data/lib/outhad/integrations/source/databrics_model/client.rb +89 -0
  185. data/lib/outhad/integrations/source/databrics_model/config/catalog.json +6 -0
  186. data/lib/outhad/integrations/source/databrics_model/config/meta.json +17 -0
  187. data/lib/outhad/integrations/source/databrics_model/config/spec.json +63 -0
  188. data/lib/outhad/integrations/source/databrics_model/icon.svg +19 -0
  189. data/lib/outhad/integrations/source/firecrawl/client.rb +151 -0
  190. data/lib/outhad/integrations/source/firecrawl/config/catalog.json +29 -0
  191. data/lib/outhad/integrations/source/firecrawl/config/meta.json +17 -0
  192. data/lib/outhad/integrations/source/firecrawl/config/spec.json +31 -0
  193. data/lib/outhad/integrations/source/firecrawl/icon.svg +4 -0
  194. data/lib/outhad/integrations/source/generic_open_ai/client.rb +118 -0
  195. data/lib/outhad/integrations/source/generic_open_ai/config/catalog.json +6 -0
  196. data/lib/outhad/integrations/source/generic_open_ai/config/meta.json +16 -0
  197. data/lib/outhad/integrations/source/generic_open_ai/config/spec.json +63 -0
  198. data/lib/outhad/integrations/source/generic_open_ai/icon.svg +6 -0
  199. data/lib/outhad/integrations/source/google_vertex_model/client.rb +83 -0
  200. data/lib/outhad/integrations/source/google_vertex_model/config/catalog.json +6 -0
  201. data/lib/outhad/integrations/source/google_vertex_model/config/meta.json +17 -0
  202. data/lib/outhad/integrations/source/google_vertex_model/config/spec.json +105 -0
  203. data/lib/outhad/integrations/source/google_vertex_model/icon.svg +2 -0
  204. data/lib/outhad/integrations/source/http_model/client.rb +108 -0
  205. data/lib/outhad/integrations/source/http_model/config/catalog.json +6 -0
  206. data/lib/outhad/integrations/source/http_model/config/meta.json +16 -0
  207. data/lib/outhad/integrations/source/http_model/config/spec.json +70 -0
  208. data/lib/outhad/integrations/source/http_model/icon.svg +9 -0
  209. data/lib/outhad/integrations/source/intuit_quick_books/client.rb +213 -0
  210. data/lib/outhad/integrations/source/intuit_quick_books/config/catalog.json +6 -0
  211. data/lib/outhad/integrations/source/intuit_quick_books/config/meta.json +17 -0
  212. data/lib/outhad/integrations/source/intuit_quick_books/config/spec.json +44 -0
  213. data/lib/outhad/integrations/source/intuit_quick_books/icon.svg +1 -0
  214. data/lib/outhad/integrations/source/maria_db/client.rb +92 -0
  215. data/lib/outhad/integrations/source/maria_db/config/meta.json +16 -0
  216. data/lib/outhad/integrations/source/maria_db/config/spec.json +48 -0
  217. data/lib/outhad/integrations/source/maria_db/icon.svg +15 -0
  218. data/lib/outhad/integrations/source/odoo/client.rb +106 -0
  219. data/lib/outhad/integrations/source/odoo/config/meta.json +15 -0
  220. data/lib/outhad/integrations/source/odoo/config/spec.json +39 -0
  221. data/lib/outhad/integrations/source/odoo/icon.svg +21 -0
  222. data/lib/outhad/integrations/source/open_ai/client.rb +118 -0
  223. data/lib/outhad/integrations/source/open_ai/config/catalog.json +6 -0
  224. data/lib/outhad/integrations/source/open_ai/config/meta.json +16 -0
  225. data/lib/outhad/integrations/source/open_ai/config/spec.json +56 -0
  226. data/lib/outhad/integrations/source/open_ai/icon.svg +1 -0
  227. data/lib/outhad/integrations/source/oracle_db/client.rb +127 -0
  228. data/lib/outhad/integrations/source/oracle_db/config/meta.json +16 -0
  229. data/lib/outhad/integrations/source/oracle_db/config/spec.json +47 -0
  230. data/lib/outhad/integrations/source/oracle_db/icon.svg +4 -0
  231. data/lib/outhad/integrations/source/pinecone_db/client.rb +73 -0
  232. data/lib/outhad/integrations/source/pinecone_db/config/catalog.json +6 -0
  233. data/lib/outhad/integrations/source/pinecone_db/config/meta.json +16 -0
  234. data/lib/outhad/integrations/source/pinecone_db/config/spec.json +34 -0
  235. data/lib/outhad/integrations/source/pinecone_db/icon.svg +2 -0
  236. data/lib/outhad/integrations/source/postgresql/client.rb +112 -0
  237. data/lib/outhad/integrations/source/postgresql/config/meta.json +16 -0
  238. data/lib/outhad/integrations/source/postgresql/config/spec.json +86 -0
  239. data/lib/outhad/integrations/source/postgresql/icon.svg +20 -0
  240. data/lib/outhad/integrations/source/qdrant/client.rb +86 -0
  241. data/lib/outhad/integrations/source/qdrant/config/catalog.json +6 -0
  242. data/lib/outhad/integrations/source/qdrant/config/meta.json +16 -0
  243. data/lib/outhad/integrations/source/qdrant/config/spec.json +29 -0
  244. data/lib/outhad/integrations/source/qdrant/icon.svg +1 -0
  245. data/lib/outhad/integrations/source/redshift/client.rb +109 -0
  246. data/lib/outhad/integrations/source/redshift/config/meta.json +16 -0
  247. data/lib/outhad/integrations/source/redshift/config/spec.json +71 -0
  248. data/lib/outhad/integrations/source/redshift/icon.svg +15 -0
  249. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/client.rb +133 -0
  250. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/catalog.json +6 -0
  251. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/meta.json +18 -0
  252. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/spec.json +53 -0
  253. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/icon.svg +16 -0
  254. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/schema_helper.rb +130 -0
  255. data/lib/outhad/integrations/source/sftp/client.rb +133 -0
  256. data/lib/outhad/integrations/source/sftp/config/meta.json +16 -0
  257. data/lib/outhad/integrations/source/sftp/config/spec.json +59 -0
  258. data/lib/outhad/integrations/source/sftp/icon.svg +1 -0
  259. data/lib/outhad/integrations/source/snowflake/client.rb +92 -0
  260. data/lib/outhad/integrations/source/snowflake/config/meta.json +16 -0
  261. data/lib/outhad/integrations/source/snowflake/config/spec.json +82 -0
  262. data/lib/outhad/integrations/source/snowflake/icon.svg +10 -0
  263. data/lib/outhad/integrations/source/watsonx_ai/client.rb +194 -0
  264. data/lib/outhad/integrations/source/watsonx_ai/config/catalog.json +6 -0
  265. data/lib/outhad/integrations/source/watsonx_ai/config/meta.json +16 -0
  266. data/lib/outhad/integrations/source/watsonx_ai/config/spec.json +74 -0
  267. data/lib/outhad/integrations/source/watsonx_ai/icon.svg +1 -0
  268. data/lib/outhad/integrations/source/watsonx_data/client.rb +146 -0
  269. data/lib/outhad/integrations/source/watsonx_data/config/meta.json +17 -0
  270. data/lib/outhad/integrations/source/watsonx_data/config/spec.json +72 -0
  271. data/lib/outhad/integrations/source/watsonx_data/icon.svg +1 -0
  272. data/lib/outhad/integrations.rb +129 -0
  273. data/outhad-integrations.gemspec +79 -0
  274. data/sig/outhad/integrations.rbs +6 -0
  275. metadata +866 -0
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad::Integrations::Destination
4
+ module MicrosoftDynamics
5
+ include Outhad::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_outhad_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.squared.ai/guides/destinations/retl-destinations/crm/microsoft_dynamics",
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", "outhad"]
14
+ }
15
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/crm/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
+ "outhad_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
+ "outhad_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>
@@ -0,0 +1,198 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad::Integrations::Destination
4
+ module MicrosoftExcel
5
+ include Outhad::Integrations::Core
6
+ class Client < DestinationConnector
7
+ prepend Outhad::Integrations::Core::RateLimiter
8
+ def check_connection(connection_config)
9
+ connection_config = connection_config.with_indifferent_access
10
+ drive_id = create_connection(connection_config)
11
+ if drive_id
12
+ success_status
13
+ else
14
+ failure_status(nil)
15
+ end
16
+ rescue StandardError => e
17
+ handle_exception(e, {
18
+ context: "MICROSOFT:EXCEL:CHECK_CONNECTION:EXCEPTION",
19
+ type: "error"
20
+ })
21
+ failure_status(e)
22
+ end
23
+
24
+ def discover(connection_config)
25
+ catalog_json = read_json(CATALOG_SPEC_PATH)
26
+ connection_config = connection_config.with_indifferent_access
27
+ token = connection_config[:token]
28
+ drive_id = create_connection(connection_config)
29
+ records = get_file(token, drive_id)
30
+ records.each do |record|
31
+ file_id = record[:id]
32
+ record[:worksheets] = get_file_data(token, drive_id, file_id)
33
+ end
34
+ catalog = Catalog.new(streams: create_streams(records, catalog_json))
35
+ catalog.to_outhad_message
36
+ rescue StandardError => e
37
+ handle_exception(e, {
38
+ context: "MICROSOFT:EXCEL:DISCOVER:EXCEPTION",
39
+ type: "error"
40
+ })
41
+ end
42
+
43
+ def write(sync_config, records, _action = "destination_insert")
44
+ connection_config = sync_config.destination.connection_specification.with_indifferent_access
45
+ token = connection_config[:token]
46
+ file_name = sync_config.stream.name.split(", ").first
47
+ sheet_name = sync_config.stream.name.split(", ").last
48
+ drive_id = create_connection(connection_config)
49
+ excel_files = get_file(token, drive_id)
50
+ worksheet = excel_files.find { |file| file[:name] == file_name }
51
+ item_id = worksheet[:id]
52
+ table = get_table(token, drive_id, item_id, sheet_name)
53
+ write_url = format(MS_EXCEL_TABLE_ROW_WRITE_API, drive_id: drive_id, item_id: item_id, sheet_name: sheet_name,
54
+ table_name: table["name"])
55
+ payload = { values: records.map(&:values) }
56
+ process_write_request(write_url, payload, token, sync_config)
57
+ end
58
+
59
+ private
60
+
61
+ def create_connection(connection_config)
62
+ token = connection_config[:token]
63
+ response = Outhad::Integrations::Core::HttpClient.request(
64
+ MS_EXCEL_AUTH_ENDPOINT,
65
+ HTTP_GET,
66
+ headers: auth_headers(token)
67
+ )
68
+ JSON.parse(response.body)["id"]
69
+ end
70
+
71
+ def get_table(token, drive_id, item_id, sheet_name)
72
+ table_url = format(MS_EXCEL_TABLE_API, drive_id: drive_id, item_id: item_id, sheet_name: sheet_name)
73
+ response = Outhad::Integrations::Core::HttpClient.request(
74
+ table_url,
75
+ HTTP_GET,
76
+ headers: auth_headers(token)
77
+ )
78
+ JSON.parse(response.body)["value"].first
79
+ end
80
+
81
+ def get_file(token, drive_id)
82
+ url = format(MS_EXCEL_FILES_API, drive_id: drive_id)
83
+ response = Outhad::Integrations::Core::HttpClient.request(
84
+ url,
85
+ HTTP_GET,
86
+ headers: auth_headers(token)
87
+ )
88
+ files = JSON.parse(response.body)["value"]
89
+ excel_files = files.select { |file| file["name"].match(/\.(xlsx|xls|xlsm)$/) }
90
+ excel_files.map { |file| { name: file["name"], id: file["id"] } }
91
+ end
92
+
93
+ def get_all_sheets(token, drive_id, item_id)
94
+ base_url = format(MS_EXCEL_WORKSHEETS_API, drive_id: drive_id, item_id: item_id)
95
+ worksheet_response = Outhad::Integrations::Core::HttpClient.request(
96
+ base_url,
97
+ HTTP_GET,
98
+ headers: auth_headers(token)
99
+ )
100
+ JSON.parse(worksheet_response.body)["value"]
101
+ end
102
+
103
+ def get_file_data(token, drive_id, item_id)
104
+ result = []
105
+ worksheets_data = get_all_sheets(token, drive_id, item_id)
106
+ worksheets_data.each do |sheet|
107
+ sheet_name = sheet["name"]
108
+ sheet_url = format(MS_EXCEL_SHEET_RANGE_API, drive_id: drive_id, item_id: item_id, sheet_name: sheet_name)
109
+
110
+ sheet_response = Outhad::Integrations::Core::HttpClient.request(
111
+ sheet_url,
112
+ HTTP_GET,
113
+ headers: auth_headers(token)
114
+ )
115
+ sheets_data = JSON.parse(sheet_response.body)
116
+ column_names = if sheets_data.key?("error")
117
+ ["Column A"]
118
+ else
119
+ sheets_data["values"].first
120
+ end
121
+ result << {
122
+ sheet_name: sheet_name,
123
+ column_names: column_names
124
+ }
125
+ end
126
+ result
127
+ end
128
+
129
+ def create_streams(records, catalog_json)
130
+ group_by_table(records).flat_map do |_, record|
131
+ record.map do |_, r|
132
+ Outhad::Integrations::Protocol::Stream.new(
133
+ name: r[:workbook],
134
+ action: StreamAction["fetch"],
135
+ json_schema: convert_to_json_schema(r[:columns]),
136
+ request_rate_limit: catalog_json["request_rate_limit"] || 60,
137
+ request_rate_limit_unit: catalog_json["request_rate_limit_unit"] || "minute",
138
+ request_rate_concurrency: catalog_json["request_rate_concurrency"] || 1
139
+ )
140
+ end
141
+ end
142
+ end
143
+
144
+ def group_by_table(records)
145
+ result = {}
146
+
147
+ records.each_with_index do |entries, entries_index|
148
+ entries[:worksheets].each_with_index do |sheet, entry_index|
149
+ workbook_sheet = "#{entries[:name]}, #{sheet[:sheet_name]}"
150
+ columns = sheet[:column_names].map do |column_name|
151
+ column_name = "empty column" if column_name.empty?
152
+ {
153
+ column_name: column_name,
154
+ data_type: "String",
155
+ is_nullable: true
156
+ }
157
+ end
158
+ result[entries_index] ||= {}
159
+ result[entries_index][entry_index] = { workbook: workbook_sheet, columns: columns }
160
+ end
161
+ end
162
+ result
163
+ end
164
+
165
+ def process_write_request(write_url, payload, token, sync_config)
166
+ write_success = 0
167
+ write_failure = 0
168
+ log_message_array = []
169
+
170
+ begin
171
+ response = Outhad::Integrations::Core::HttpClient.request(
172
+ write_url,
173
+ HTTP_POST,
174
+ payload: payload,
175
+ headers: auth_headers(token)
176
+ )
177
+ if success?(response)
178
+ write_success += 1
179
+ else
180
+ write_failure += 1
181
+ end
182
+ log_message_array << log_request_response("info", [HTTP_POST, write_url, payload], response)
183
+ rescue StandardError => e
184
+ handle_exception(e, {
185
+ context: "MICROSOFT:EXCEL:RECORD:WRITE:EXCEPTION",
186
+ type: "error",
187
+ sync_id: sync_config.sync_id,
188
+ sync_run_id: sync_config.sync_run_id
189
+ })
190
+ write_failure += 1
191
+ log_message_array << log_request_response("error", [HTTP_POST, write_url, payload], e.message)
192
+ end
193
+
194
+ tracking_message(write_success, write_failure, log_message_array)
195
+ end
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,7 @@
1
+ {
2
+ "request_rate_limit": 6000,
3
+ "request_rate_limit_unit": "minute",
4
+ "request_rate_concurrency": 1,
5
+ "streams": []
6
+ }
7
+
@@ -0,0 +1,15 @@
1
+ {
2
+ "data": {
3
+ "name": "MicrosoftExcel",
4
+ "title": "Microsoft Excel",
5
+ "connector_type": "destination",
6
+ "category": "Database",
7
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/productivity-tools/microsoft-excel",
8
+ "github_issue_label": "destination-microsoft-excel",
9
+ "icon": "icon.svg",
10
+ "license": "MIT",
11
+ "release_stage": "alpha",
12
+ "support_level": "community",
13
+ "tags": ["language:ruby", "outhad"]
14
+ }
15
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "documentation_url": "https://docs.squared.ai/guides/destinations/retl-destinations/productivity-tools/microsoft-excel",
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 Excel",
8
+ "type": "object",
9
+ "required": ["token"],
10
+ "properties": {
11
+ "token": {
12
+ "description": "Token from Microsoft Graph.",
13
+ "type": "string",
14
+ "title": "Token",
15
+ "order": 0
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,18 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="800" width="1200" viewBox="-343.4625 -532.5 2976.675 3195">
2
+ <path d="M1437.75 1011.75L532.5 852v1180.393c0 53.907 43.7 97.607 97.607 97.607h1562.036c53.907 0 97.607-43.7 97.607-97.607V1597.5z" fill="#185C37"/>
3
+ <path d="M1437.75 0H630.107C576.2 0 532.5 43.7 532.5 97.607V532.5l905.25 532.5L1917 1224.75 2289.75 1065V532.5z" fill="#21A366"/>
4
+ <path d="M532.5 532.5h905.25V1065H532.5z" fill="#107C41"/>
5
+ <path d="M1180.393 426H532.5v1331.25h647.893c53.834-.175 97.432-43.773 97.607-97.607V523.607c-.175-53.834-43.773-97.432-97.607-97.607z" opacity=".1"/>
6
+ <path d="M1127.143 479.25H532.5V1810.5h594.643c53.834-.175 97.432-43.773 97.607-97.607V576.857c-.175-53.834-43.773-97.432-97.607-97.607z" opacity=".2"/>
7
+ <path d="M1127.143 479.25H532.5V1704h594.643c53.834-.175 97.432-43.773 97.607-97.607V576.857c-.175-53.834-43.773-97.432-97.607-97.607z" opacity=".2"/>
8
+ <path d="M1073.893 479.25H532.5V1704h541.393c53.834-.175 97.432-43.773 97.607-97.607V576.857c-.175-53.834-43.773-97.432-97.607-97.607z" opacity=".2"/>
9
+ <linearGradient gradientTransform="matrix(1 0 0 -1 0 2132)" y2="404.982" x2="967.987" y1="1729.018" x1="203.513" gradientUnits="userSpaceOnUse" id="a">
10
+ <stop offset="0" stop-color="#18884f"/>
11
+ <stop offset=".5" stop-color="#117e43"/>
12
+ <stop offset="1" stop-color="#0b6631"/>
13
+ </linearGradient>
14
+ <path d="M97.607 479.25h976.285c53.907 0 97.607 43.7 97.607 97.607v976.285c0 53.907-43.7 97.607-97.607 97.607H97.607C43.7 1650.75 0 1607.05 0 1553.143V576.857c0-53.907 43.7-97.607 97.607-97.607z" fill="url(#a)"/>
15
+ <path d="M302.3 1382.264l205.332-318.169L319.5 747.683h151.336l102.666 202.35c9.479 19.223 15.975 33.494 19.49 42.919h1.331a798.667 798.667 0 0121.3-44.677L725.371 747.79H864.3l-192.925 314.548L869.2 1382.263H721.378L602.79 1160.158a186.298 186.298 0 01-14.164-29.66h-1.757a140.458 140.458 0 01-13.739 28.755l-122.102 223.011z" fill="#FFF"/>
16
+ <path d="M2192.143 0H1437.75v532.5h852V97.607C2289.75 43.7 2246.05 0 2192.143 0z" fill="#33C481"/>
17
+ <path d="M1437.75 1065h852v532.5h-852z" fill="#107C41"/>
18
+ </svg>