webhookdb 0.1.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 (364) hide show
  1. checksums.yaml +7 -0
  2. data/data/messages/layouts/blank.email.liquid +10 -0
  3. data/data/messages/layouts/minimal.email.liquid +28 -0
  4. data/data/messages/layouts/standard.email.liquid +28 -0
  5. data/data/messages/partials/button.liquid +15 -0
  6. data/data/messages/partials/environment_banner.liquid +9 -0
  7. data/data/messages/partials/footer.liquid +22 -0
  8. data/data/messages/partials/greeting.liquid +3 -0
  9. data/data/messages/partials/logo_header.liquid +18 -0
  10. data/data/messages/partials/signoff.liquid +1 -0
  11. data/data/messages/styles/v1.liquid +346 -0
  12. data/data/messages/templates/errors/icalendar_fetch.email.liquid +29 -0
  13. data/data/messages/templates/invite.email.liquid +15 -0
  14. data/data/messages/templates/new_customer.email.liquid +24 -0
  15. data/data/messages/templates/org_database_migration_finished.email.liquid +7 -0
  16. data/data/messages/templates/org_database_migration_started.email.liquid +9 -0
  17. data/data/messages/templates/specs/_field_partial.liquid +1 -0
  18. data/data/messages/templates/specs/basic.email.liquid +2 -0
  19. data/data/messages/templates/specs/basic.fake.liquid +1 -0
  20. data/data/messages/templates/specs/with_field.email.liquid +2 -0
  21. data/data/messages/templates/specs/with_field.fake.liquid +1 -0
  22. data/data/messages/templates/specs/with_include.email.liquid +2 -0
  23. data/data/messages/templates/specs/with_partial.email.liquid +1 -0
  24. data/data/messages/templates/verification.email.liquid +14 -0
  25. data/data/messages/templates/verification.sms.liquid +1 -0
  26. data/data/messages/web/install-customer-login.liquid +48 -0
  27. data/data/messages/web/install-error.liquid +17 -0
  28. data/data/messages/web/install-success.liquid +35 -0
  29. data/data/messages/web/install.liquid +20 -0
  30. data/data/messages/web/partials/footer.liquid +4 -0
  31. data/data/messages/web/partials/form_error.liquid +1 -0
  32. data/data/messages/web/partials/header.liquid +3 -0
  33. data/data/messages/web/styles.liquid +134 -0
  34. data/data/windows_tz.txt +461 -0
  35. data/db/migrations/001_testing_pixies.rb +13 -0
  36. data/db/migrations/002_initial.rb +132 -0
  37. data/db/migrations/003_ux_overhaul.rb +20 -0
  38. data/db/migrations/004_incremental_backfill.rb +9 -0
  39. data/db/migrations/005_log_webhooks.rb +24 -0
  40. data/db/migrations/006_generalize_roles.rb +29 -0
  41. data/db/migrations/007_org_dns.rb +12 -0
  42. data/db/migrations/008_webhook_subscriptions.rb +19 -0
  43. data/db/migrations/009_nonunique_stripe_subscription_customer.rb +16 -0
  44. data/db/migrations/010_drop_integration_soft_delete.rb +14 -0
  45. data/db/migrations/011_webhook_subscriptions_created_at.rb +10 -0
  46. data/db/migrations/012_webhook_subscriptions_created_by.rb +9 -0
  47. data/db/migrations/013_default_org_membership.rb +30 -0
  48. data/db/migrations/014_webhook_subscription_deliveries.rb +26 -0
  49. data/db/migrations/015_dependent_integrations.rb +9 -0
  50. data/db/migrations/016_encrypted_columns.rb +9 -0
  51. data/db/migrations/017_skip_verification.rb +9 -0
  52. data/db/migrations/018_sync_targets.rb +25 -0
  53. data/db/migrations/019_org_schema.rb +9 -0
  54. data/db/migrations/020_org_database_migrations.rb +25 -0
  55. data/db/migrations/021_no_default_org_schema.rb +14 -0
  56. data/db/migrations/022_database_document.rb +15 -0
  57. data/db/migrations/023_sync_target_schema.rb +9 -0
  58. data/db/migrations/024_org_semaphore_jobs.rb +9 -0
  59. data/db/migrations/025_integration_backfill_cursor.rb +9 -0
  60. data/db/migrations/026_undo_integration_backfill_cursor.rb +9 -0
  61. data/db/migrations/027_sync_target_http_sync.rb +12 -0
  62. data/db/migrations/028_logged_webhook_path.rb +24 -0
  63. data/db/migrations/029_encrypt_columns.rb +97 -0
  64. data/db/migrations/030_org_sync_target_timeout.rb +9 -0
  65. data/db/migrations/031_org_max_query_rows.rb +9 -0
  66. data/db/migrations/032_remove_db_defaults.rb +12 -0
  67. data/db/migrations/033_backfill_jobs.rb +26 -0
  68. data/db/migrations/034_backfill_job_criteria.rb +9 -0
  69. data/db/migrations/035_synchronous_backfill.rb +9 -0
  70. data/db/migrations/036_oauth.rb +26 -0
  71. data/db/migrations/037_oauth_used.rb +9 -0
  72. data/lib/amigo/durable_job.rb +416 -0
  73. data/lib/pry/clipboard.rb +111 -0
  74. data/lib/sequel/advisory_lock.rb +65 -0
  75. data/lib/webhookdb/admin.rb +4 -0
  76. data/lib/webhookdb/admin_api/auth.rb +36 -0
  77. data/lib/webhookdb/admin_api/customers.rb +63 -0
  78. data/lib/webhookdb/admin_api/database_documents.rb +20 -0
  79. data/lib/webhookdb/admin_api/entities.rb +66 -0
  80. data/lib/webhookdb/admin_api/message_deliveries.rb +61 -0
  81. data/lib/webhookdb/admin_api/roles.rb +15 -0
  82. data/lib/webhookdb/admin_api.rb +34 -0
  83. data/lib/webhookdb/aggregate_result.rb +63 -0
  84. data/lib/webhookdb/api/auth.rb +122 -0
  85. data/lib/webhookdb/api/connstr_auth.rb +36 -0
  86. data/lib/webhookdb/api/db.rb +188 -0
  87. data/lib/webhookdb/api/demo.rb +14 -0
  88. data/lib/webhookdb/api/entities.rb +198 -0
  89. data/lib/webhookdb/api/helpers.rb +253 -0
  90. data/lib/webhookdb/api/install.rb +296 -0
  91. data/lib/webhookdb/api/me.rb +53 -0
  92. data/lib/webhookdb/api/organizations.rb +254 -0
  93. data/lib/webhookdb/api/replay.rb +64 -0
  94. data/lib/webhookdb/api/service_integrations.rb +402 -0
  95. data/lib/webhookdb/api/services.rb +27 -0
  96. data/lib/webhookdb/api/stripe.rb +22 -0
  97. data/lib/webhookdb/api/subscriptions.rb +67 -0
  98. data/lib/webhookdb/api/sync_targets.rb +232 -0
  99. data/lib/webhookdb/api/system.rb +37 -0
  100. data/lib/webhookdb/api/webhook_subscriptions.rb +96 -0
  101. data/lib/webhookdb/api.rb +92 -0
  102. data/lib/webhookdb/apps.rb +93 -0
  103. data/lib/webhookdb/async/audit_logger.rb +38 -0
  104. data/lib/webhookdb/async/autoscaler.rb +84 -0
  105. data/lib/webhookdb/async/job.rb +18 -0
  106. data/lib/webhookdb/async/job_logger.rb +45 -0
  107. data/lib/webhookdb/async/scheduled_job.rb +18 -0
  108. data/lib/webhookdb/async.rb +142 -0
  109. data/lib/webhookdb/aws.rb +98 -0
  110. data/lib/webhookdb/backfill_job.rb +107 -0
  111. data/lib/webhookdb/backfiller.rb +107 -0
  112. data/lib/webhookdb/cloudflare.rb +39 -0
  113. data/lib/webhookdb/connection_cache.rb +177 -0
  114. data/lib/webhookdb/console.rb +71 -0
  115. data/lib/webhookdb/convertkit.rb +14 -0
  116. data/lib/webhookdb/crypto.rb +66 -0
  117. data/lib/webhookdb/customer/reset_code.rb +94 -0
  118. data/lib/webhookdb/customer.rb +347 -0
  119. data/lib/webhookdb/database_document.rb +72 -0
  120. data/lib/webhookdb/db_adapter/column_types.rb +37 -0
  121. data/lib/webhookdb/db_adapter/default_sql.rb +187 -0
  122. data/lib/webhookdb/db_adapter/pg.rb +96 -0
  123. data/lib/webhookdb/db_adapter/snowflake.rb +137 -0
  124. data/lib/webhookdb/db_adapter.rb +208 -0
  125. data/lib/webhookdb/dbutil.rb +92 -0
  126. data/lib/webhookdb/demo_mode.rb +100 -0
  127. data/lib/webhookdb/developer_alert.rb +51 -0
  128. data/lib/webhookdb/email_octopus.rb +21 -0
  129. data/lib/webhookdb/enumerable.rb +18 -0
  130. data/lib/webhookdb/fixtures/backfill_jobs.rb +72 -0
  131. data/lib/webhookdb/fixtures/customers.rb +65 -0
  132. data/lib/webhookdb/fixtures/database_documents.rb +27 -0
  133. data/lib/webhookdb/fixtures/faker.rb +41 -0
  134. data/lib/webhookdb/fixtures/logged_webhooks.rb +56 -0
  135. data/lib/webhookdb/fixtures/message_deliveries.rb +59 -0
  136. data/lib/webhookdb/fixtures/oauth_sessions.rb +24 -0
  137. data/lib/webhookdb/fixtures/organization_database_migrations.rb +37 -0
  138. data/lib/webhookdb/fixtures/organization_memberships.rb +54 -0
  139. data/lib/webhookdb/fixtures/organizations.rb +32 -0
  140. data/lib/webhookdb/fixtures/reset_codes.rb +23 -0
  141. data/lib/webhookdb/fixtures/service_integrations.rb +42 -0
  142. data/lib/webhookdb/fixtures/subscriptions.rb +33 -0
  143. data/lib/webhookdb/fixtures/sync_targets.rb +32 -0
  144. data/lib/webhookdb/fixtures/webhook_subscriptions.rb +35 -0
  145. data/lib/webhookdb/fixtures.rb +15 -0
  146. data/lib/webhookdb/formatting.rb +56 -0
  147. data/lib/webhookdb/front.rb +49 -0
  148. data/lib/webhookdb/github.rb +22 -0
  149. data/lib/webhookdb/google_calendar.rb +29 -0
  150. data/lib/webhookdb/heroku.rb +21 -0
  151. data/lib/webhookdb/http.rb +114 -0
  152. data/lib/webhookdb/icalendar.rb +17 -0
  153. data/lib/webhookdb/id.rb +17 -0
  154. data/lib/webhookdb/idempotency.rb +90 -0
  155. data/lib/webhookdb/increase.rb +42 -0
  156. data/lib/webhookdb/intercom.rb +23 -0
  157. data/lib/webhookdb/jobs/amigo_test_jobs.rb +118 -0
  158. data/lib/webhookdb/jobs/backfill.rb +32 -0
  159. data/lib/webhookdb/jobs/create_mirror_table.rb +18 -0
  160. data/lib/webhookdb/jobs/create_stripe_customer.rb +17 -0
  161. data/lib/webhookdb/jobs/customer_created_notify_internal.rb +22 -0
  162. data/lib/webhookdb/jobs/demo_mode_sync_data.rb +19 -0
  163. data/lib/webhookdb/jobs/deprecated_jobs.rb +19 -0
  164. data/lib/webhookdb/jobs/developer_alert_handle.rb +14 -0
  165. data/lib/webhookdb/jobs/durable_job_recheck_poller.rb +17 -0
  166. data/lib/webhookdb/jobs/emailer.rb +15 -0
  167. data/lib/webhookdb/jobs/icalendar_enqueue_syncs.rb +25 -0
  168. data/lib/webhookdb/jobs/icalendar_sync.rb +23 -0
  169. data/lib/webhookdb/jobs/logged_webhook_replay.rb +17 -0
  170. data/lib/webhookdb/jobs/logged_webhook_resilient_replay.rb +15 -0
  171. data/lib/webhookdb/jobs/message_dispatched.rb +16 -0
  172. data/lib/webhookdb/jobs/organization_database_migration_notify_finished.rb +21 -0
  173. data/lib/webhookdb/jobs/organization_database_migration_notify_started.rb +21 -0
  174. data/lib/webhookdb/jobs/organization_database_migration_run.rb +24 -0
  175. data/lib/webhookdb/jobs/prepare_database_connections.rb +22 -0
  176. data/lib/webhookdb/jobs/process_webhook.rb +47 -0
  177. data/lib/webhookdb/jobs/renew_watch_channel.rb +24 -0
  178. data/lib/webhookdb/jobs/replication_migration.rb +24 -0
  179. data/lib/webhookdb/jobs/reset_code_create_dispatch.rb +23 -0
  180. data/lib/webhookdb/jobs/scheduled_backfills.rb +77 -0
  181. data/lib/webhookdb/jobs/send_invite.rb +15 -0
  182. data/lib/webhookdb/jobs/send_test_webhook.rb +25 -0
  183. data/lib/webhookdb/jobs/send_webhook.rb +20 -0
  184. data/lib/webhookdb/jobs/sync_target_enqueue_scheduled.rb +16 -0
  185. data/lib/webhookdb/jobs/sync_target_run_sync.rb +38 -0
  186. data/lib/webhookdb/jobs/trim_logged_webhooks.rb +15 -0
  187. data/lib/webhookdb/jobs/webhook_resource_notify_integrations.rb +30 -0
  188. data/lib/webhookdb/jobs/webhook_subscription_delivery_attempt.rb +29 -0
  189. data/lib/webhookdb/jobs.rb +4 -0
  190. data/lib/webhookdb/json.rb +113 -0
  191. data/lib/webhookdb/liquid/expose.rb +27 -0
  192. data/lib/webhookdb/liquid/filters.rb +16 -0
  193. data/lib/webhookdb/liquid/liquification.rb +26 -0
  194. data/lib/webhookdb/liquid/partial.rb +12 -0
  195. data/lib/webhookdb/logged_webhook/resilient.rb +95 -0
  196. data/lib/webhookdb/logged_webhook.rb +194 -0
  197. data/lib/webhookdb/message/body.rb +25 -0
  198. data/lib/webhookdb/message/delivery.rb +127 -0
  199. data/lib/webhookdb/message/email_transport.rb +133 -0
  200. data/lib/webhookdb/message/fake_transport.rb +54 -0
  201. data/lib/webhookdb/message/liquid_drops.rb +29 -0
  202. data/lib/webhookdb/message/template.rb +89 -0
  203. data/lib/webhookdb/message/transport.rb +43 -0
  204. data/lib/webhookdb/message.rb +150 -0
  205. data/lib/webhookdb/messages/error_icalendar_fetch.rb +42 -0
  206. data/lib/webhookdb/messages/invite.rb +23 -0
  207. data/lib/webhookdb/messages/new_customer.rb +14 -0
  208. data/lib/webhookdb/messages/org_database_migration_finished.rb +23 -0
  209. data/lib/webhookdb/messages/org_database_migration_started.rb +24 -0
  210. data/lib/webhookdb/messages/specs.rb +57 -0
  211. data/lib/webhookdb/messages/verification.rb +23 -0
  212. data/lib/webhookdb/method_utilities.rb +82 -0
  213. data/lib/webhookdb/microsoft_calendar.rb +36 -0
  214. data/lib/webhookdb/nextpax.rb +14 -0
  215. data/lib/webhookdb/oauth/front.rb +58 -0
  216. data/lib/webhookdb/oauth/intercom.rb +58 -0
  217. data/lib/webhookdb/oauth/session.rb +24 -0
  218. data/lib/webhookdb/oauth.rb +80 -0
  219. data/lib/webhookdb/organization/alerting.rb +35 -0
  220. data/lib/webhookdb/organization/database_migration.rb +151 -0
  221. data/lib/webhookdb/organization/db_builder.rb +429 -0
  222. data/lib/webhookdb/organization.rb +506 -0
  223. data/lib/webhookdb/organization_membership.rb +58 -0
  224. data/lib/webhookdb/phone_number.rb +38 -0
  225. data/lib/webhookdb/plaid.rb +23 -0
  226. data/lib/webhookdb/platform.rb +27 -0
  227. data/lib/webhookdb/plivo.rb +52 -0
  228. data/lib/webhookdb/postgres/maintenance.rb +166 -0
  229. data/lib/webhookdb/postgres/model.rb +82 -0
  230. data/lib/webhookdb/postgres/model_utilities.rb +382 -0
  231. data/lib/webhookdb/postgres/testing_pixie.rb +16 -0
  232. data/lib/webhookdb/postgres/validations.rb +46 -0
  233. data/lib/webhookdb/postgres.rb +176 -0
  234. data/lib/webhookdb/postmark.rb +20 -0
  235. data/lib/webhookdb/redis.rb +35 -0
  236. data/lib/webhookdb/replicator/atom_single_feed_v1.rb +116 -0
  237. data/lib/webhookdb/replicator/aws_pricing_v1.rb +488 -0
  238. data/lib/webhookdb/replicator/base.rb +1185 -0
  239. data/lib/webhookdb/replicator/column.rb +482 -0
  240. data/lib/webhookdb/replicator/convertkit_broadcast_v1.rb +69 -0
  241. data/lib/webhookdb/replicator/convertkit_subscriber_v1.rb +200 -0
  242. data/lib/webhookdb/replicator/convertkit_tag_v1.rb +66 -0
  243. data/lib/webhookdb/replicator/convertkit_v1_mixin.rb +65 -0
  244. data/lib/webhookdb/replicator/docgen.rb +167 -0
  245. data/lib/webhookdb/replicator/email_octopus_campaign_v1.rb +84 -0
  246. data/lib/webhookdb/replicator/email_octopus_contact_v1.rb +159 -0
  247. data/lib/webhookdb/replicator/email_octopus_event_v1.rb +244 -0
  248. data/lib/webhookdb/replicator/email_octopus_list_v1.rb +101 -0
  249. data/lib/webhookdb/replicator/fake.rb +453 -0
  250. data/lib/webhookdb/replicator/front_conversation_v1.rb +45 -0
  251. data/lib/webhookdb/replicator/front_marketplace_root_v1.rb +55 -0
  252. data/lib/webhookdb/replicator/front_message_v1.rb +45 -0
  253. data/lib/webhookdb/replicator/front_v1_mixin.rb +22 -0
  254. data/lib/webhookdb/replicator/github_issue_comment_v1.rb +58 -0
  255. data/lib/webhookdb/replicator/github_issue_v1.rb +83 -0
  256. data/lib/webhookdb/replicator/github_pull_v1.rb +84 -0
  257. data/lib/webhookdb/replicator/github_release_v1.rb +47 -0
  258. data/lib/webhookdb/replicator/github_repo_v1_mixin.rb +250 -0
  259. data/lib/webhookdb/replicator/github_repository_event_v1.rb +45 -0
  260. data/lib/webhookdb/replicator/icalendar_calendar_v1.rb +465 -0
  261. data/lib/webhookdb/replicator/icalendar_event_v1.rb +334 -0
  262. data/lib/webhookdb/replicator/increase_account_number_v1.rb +77 -0
  263. data/lib/webhookdb/replicator/increase_account_transfer_v1.rb +61 -0
  264. data/lib/webhookdb/replicator/increase_account_v1.rb +63 -0
  265. data/lib/webhookdb/replicator/increase_ach_transfer_v1.rb +78 -0
  266. data/lib/webhookdb/replicator/increase_check_transfer_v1.rb +64 -0
  267. data/lib/webhookdb/replicator/increase_limit_v1.rb +78 -0
  268. data/lib/webhookdb/replicator/increase_transaction_v1.rb +74 -0
  269. data/lib/webhookdb/replicator/increase_v1_mixin.rb +121 -0
  270. data/lib/webhookdb/replicator/increase_wire_transfer_v1.rb +61 -0
  271. data/lib/webhookdb/replicator/intercom_contact_v1.rb +36 -0
  272. data/lib/webhookdb/replicator/intercom_conversation_v1.rb +38 -0
  273. data/lib/webhookdb/replicator/intercom_marketplace_root_v1.rb +69 -0
  274. data/lib/webhookdb/replicator/intercom_v1_mixin.rb +105 -0
  275. data/lib/webhookdb/replicator/oauth_refresh_access_token_mixin.rb +65 -0
  276. data/lib/webhookdb/replicator/plivo_sms_inbound_v1.rb +102 -0
  277. data/lib/webhookdb/replicator/postmark_inbound_message_v1.rb +94 -0
  278. data/lib/webhookdb/replicator/postmark_outbound_message_event_v1.rb +107 -0
  279. data/lib/webhookdb/replicator/schema_modification.rb +42 -0
  280. data/lib/webhookdb/replicator/shopify_customer_v1.rb +58 -0
  281. data/lib/webhookdb/replicator/shopify_order_v1.rb +64 -0
  282. data/lib/webhookdb/replicator/shopify_v1_mixin.rb +161 -0
  283. data/lib/webhookdb/replicator/signalwire_message_v1.rb +169 -0
  284. data/lib/webhookdb/replicator/sponsy_customer_v1.rb +54 -0
  285. data/lib/webhookdb/replicator/sponsy_placement_v1.rb +34 -0
  286. data/lib/webhookdb/replicator/sponsy_publication_v1.rb +125 -0
  287. data/lib/webhookdb/replicator/sponsy_slot_v1.rb +41 -0
  288. data/lib/webhookdb/replicator/sponsy_status_v1.rb +35 -0
  289. data/lib/webhookdb/replicator/sponsy_v1_mixin.rb +165 -0
  290. data/lib/webhookdb/replicator/state_machine_step.rb +69 -0
  291. data/lib/webhookdb/replicator/stripe_charge_v1.rb +77 -0
  292. data/lib/webhookdb/replicator/stripe_coupon_v1.rb +62 -0
  293. data/lib/webhookdb/replicator/stripe_customer_v1.rb +60 -0
  294. data/lib/webhookdb/replicator/stripe_dispute_v1.rb +77 -0
  295. data/lib/webhookdb/replicator/stripe_invoice_item_v1.rb +82 -0
  296. data/lib/webhookdb/replicator/stripe_invoice_v1.rb +116 -0
  297. data/lib/webhookdb/replicator/stripe_payout_v1.rb +67 -0
  298. data/lib/webhookdb/replicator/stripe_price_v1.rb +60 -0
  299. data/lib/webhookdb/replicator/stripe_product_v1.rb +60 -0
  300. data/lib/webhookdb/replicator/stripe_refund_v1.rb +101 -0
  301. data/lib/webhookdb/replicator/stripe_subscription_item_v1.rb +56 -0
  302. data/lib/webhookdb/replicator/stripe_subscription_v1.rb +75 -0
  303. data/lib/webhookdb/replicator/stripe_v1_mixin.rb +116 -0
  304. data/lib/webhookdb/replicator/transistor_episode_stats_v1.rb +141 -0
  305. data/lib/webhookdb/replicator/transistor_episode_v1.rb +169 -0
  306. data/lib/webhookdb/replicator/transistor_show_v1.rb +68 -0
  307. data/lib/webhookdb/replicator/transistor_v1_mixin.rb +65 -0
  308. data/lib/webhookdb/replicator/twilio_sms_v1.rb +156 -0
  309. data/lib/webhookdb/replicator/webhook_request.rb +5 -0
  310. data/lib/webhookdb/replicator/webhookdb_customer_v1.rb +74 -0
  311. data/lib/webhookdb/replicator.rb +224 -0
  312. data/lib/webhookdb/role.rb +42 -0
  313. data/lib/webhookdb/sentry.rb +35 -0
  314. data/lib/webhookdb/service/auth.rb +138 -0
  315. data/lib/webhookdb/service/collection.rb +91 -0
  316. data/lib/webhookdb/service/entities.rb +97 -0
  317. data/lib/webhookdb/service/helpers.rb +270 -0
  318. data/lib/webhookdb/service/middleware.rb +124 -0
  319. data/lib/webhookdb/service/types.rb +30 -0
  320. data/lib/webhookdb/service/validators.rb +32 -0
  321. data/lib/webhookdb/service/view_api.rb +63 -0
  322. data/lib/webhookdb/service.rb +219 -0
  323. data/lib/webhookdb/service_integration.rb +332 -0
  324. data/lib/webhookdb/shopify.rb +35 -0
  325. data/lib/webhookdb/signalwire.rb +13 -0
  326. data/lib/webhookdb/slack.rb +68 -0
  327. data/lib/webhookdb/snowflake.rb +90 -0
  328. data/lib/webhookdb/spec_helpers/async.rb +122 -0
  329. data/lib/webhookdb/spec_helpers/citest.rb +88 -0
  330. data/lib/webhookdb/spec_helpers/integration.rb +121 -0
  331. data/lib/webhookdb/spec_helpers/message.rb +41 -0
  332. data/lib/webhookdb/spec_helpers/postgres.rb +220 -0
  333. data/lib/webhookdb/spec_helpers/service.rb +432 -0
  334. data/lib/webhookdb/spec_helpers/shared_examples_for_columns.rb +56 -0
  335. data/lib/webhookdb/spec_helpers/shared_examples_for_replicators.rb +915 -0
  336. data/lib/webhookdb/spec_helpers/whdb.rb +139 -0
  337. data/lib/webhookdb/spec_helpers.rb +63 -0
  338. data/lib/webhookdb/sponsy.rb +14 -0
  339. data/lib/webhookdb/stripe.rb +37 -0
  340. data/lib/webhookdb/subscription.rb +203 -0
  341. data/lib/webhookdb/sync_target.rb +491 -0
  342. data/lib/webhookdb/tasks/admin.rb +49 -0
  343. data/lib/webhookdb/tasks/annotate.rb +36 -0
  344. data/lib/webhookdb/tasks/db.rb +82 -0
  345. data/lib/webhookdb/tasks/docs.rb +42 -0
  346. data/lib/webhookdb/tasks/fixture.rb +35 -0
  347. data/lib/webhookdb/tasks/message.rb +50 -0
  348. data/lib/webhookdb/tasks/regress.rb +87 -0
  349. data/lib/webhookdb/tasks/release.rb +27 -0
  350. data/lib/webhookdb/tasks/sidekiq.rb +23 -0
  351. data/lib/webhookdb/tasks/specs.rb +64 -0
  352. data/lib/webhookdb/theranest.rb +15 -0
  353. data/lib/webhookdb/transistor.rb +13 -0
  354. data/lib/webhookdb/twilio.rb +13 -0
  355. data/lib/webhookdb/typed_struct.rb +44 -0
  356. data/lib/webhookdb/version.rb +5 -0
  357. data/lib/webhookdb/webhook_response.rb +50 -0
  358. data/lib/webhookdb/webhook_subscription/delivery.rb +82 -0
  359. data/lib/webhookdb/webhook_subscription.rb +226 -0
  360. data/lib/webhookdb/windows_tz.rb +32 -0
  361. data/lib/webhookdb/xml.rb +92 -0
  362. data/lib/webhookdb.rb +224 -0
  363. data/lib/webterm/apps.rb +45 -0
  364. metadata +1129 -0
@@ -0,0 +1,402 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+ require "oj"
5
+
6
+ require "webhookdb/api"
7
+ require "webhookdb/formatting"
8
+ require "webhookdb/replicator"
9
+ require "webhookdb/async/audit_logger"
10
+ require "webhookdb/jobs/process_webhook"
11
+
12
+ class Webhookdb::API::ServiceIntegrations < Webhookdb::API::V1
13
+ # These URLs are not used by the CLI-
14
+ # they are the url that customers should point their webhooks to.
15
+ # We can't check org permissions on this endpoint
16
+ # because external services (so no auth) will be posting webhooks here.
17
+ # Depend on webhook verification to ensure the request is valid.
18
+ resource :service_integrations do
19
+ route [:post, :put, :delete, :patch], "/:opaque_id*" do
20
+ opaque_id = params[:opaque_id]
21
+ handle_webhook_request(opaque_id) do
22
+ Webhookdb::ServiceIntegration[opaque_id:] or merror!(400, "No integration with that id")
23
+ end
24
+ end
25
+ end
26
+
27
+ resource :organizations do
28
+ route_param :org_identifier, type: String do
29
+ resource :service_integrations do
30
+ desc "Return all integrations associated with the organization."
31
+ get do
32
+ integrations = lookup_org!.service_integrations
33
+ message = ""
34
+ if integrations.empty?
35
+ message = "This organization doesn't have any integrations set up yet.\n" \
36
+ "Use `webhookdb services list` and `webhookdb integrations create` to set one up."
37
+ end
38
+ present_collection integrations, with: Webhookdb::API::ServiceIntegrationEntity, message:
39
+ end
40
+
41
+ resource :create do
42
+ helpers do
43
+ def create_integration(org, name)
44
+ available_services_list = org.available_replicator_names.sort.join("\n\t")
45
+
46
+ service_name_invalid = Webhookdb::Replicator.registered(name).nil?
47
+ if service_name_invalid
48
+ message = %(WebhookDB doesn't support a service called '#{name}.'
49
+ These are all the services currently supported by WebhookDB:
50
+
51
+ \t#{available_services_list}
52
+
53
+ Run `webhookdb services list` to see available services, and try again with the new name.)
54
+ merror!(400, message, code: "invalid_service", alert: true)
55
+ end
56
+
57
+ # If org does not have access to the given service
58
+ unless org.available_replicator_names.include?(name)
59
+ step = Webhookdb::Replicator::StateMachineStep.new
60
+ step.needs_input = false
61
+ step.output =
62
+ %(
63
+ Your organization does not have permission to view the service called '#{name}.' These are all the services
64
+ you currently have access to:
65
+
66
+ \t#{available_services_list}
67
+
68
+ You can run `webhookdb services list` at any time to see the list of services available to your organization.
69
+ If the list does not look correct, you can contact support at #{Webhookdb.support_email}.)
70
+ step.complete = true
71
+ return step
72
+ end
73
+ sint = Webhookdb::ServiceIntegration.create_disambiguated(name, organization: org)
74
+ replicator = sint.replicator
75
+ # We always want to enqueue the backfill job if it is possible to do so, even if
76
+ # we are not returning the backfill step in our response to this create request
77
+ if replicator.descriptor.supports_backfill?
78
+ backfill_step, _job = replicator.calculate_and_backfill_state_machine(incremental: true)
79
+ end
80
+
81
+ # Prefer creating using webhooks, not backfilling, but fall back to backfilling.
82
+ return replicator.calculate_webhook_state_machine if replicator.descriptor.supports_webhooks?
83
+ return backfill_step
84
+ end
85
+
86
+ def verify_unique_integration(org)
87
+ existing = Webhookdb::ServiceIntegration.where(
88
+ organization: org,
89
+ service_name: params[:service_name],
90
+ ).first
91
+ return if existing.nil?
92
+ return if params.key?(:guard_confirm)
93
+ Webhookdb::API::Helpers.prompt_for_required_param!(
94
+ request,
95
+ :guard_confirm,
96
+ "WARNING: #{org.name} already has an integration for service #{params[:service_name]}.\n" \
97
+ "Press Enter to create another, or Ctrl+C to quit.\n" \
98
+ "Modify the existing integration using `webhookdb integrations #{existing.opaque_id} setup`",
99
+ )
100
+ end
101
+ end
102
+ desc "Create service integration on a given organization"
103
+ params do
104
+ optional :service_name, type: String,
105
+ prompt: "Enter the name of the service to create an integration for.\n" \
106
+ "Run 'webhookdb services list' to see available services:"
107
+ optional :guard_confirm
108
+ end
109
+ post do
110
+ customer = current_customer
111
+ org = lookup_org!
112
+ merror!(402, "You have reached the maximum number of free integrations", alert: true) unless
113
+ org.can_add_new_integration?
114
+ ensure_admin!
115
+ verify_unique_integration(org)
116
+ step = nil
117
+ customer.db.transaction do
118
+ step = create_integration(org, params[:service_name])
119
+ # No reason to create the integration when this happens.
120
+ # We may want to expand the situations we roll back,
121
+ # but we start by being targeted.
122
+ raise Sequel::Rollback if step.error_code == "no_candidate_dependency"
123
+ end
124
+ status 200
125
+ present step, with: Webhookdb::API::StateMachineEntity
126
+ end
127
+ end
128
+
129
+ route_param :sint_identifier, type: String do
130
+ helpers do
131
+ def ensure_plan_supports!(org=nil)
132
+ org ||= lookup_org!
133
+ sint = lookup_service_integration!(org, params[:sint_identifier])
134
+ return if sint.plan_supports_integration?
135
+ err_msg = "This integration is no longer supported. " \
136
+ "Run `webhookdb subscription edit` to manage your subscription."
137
+ merror!(402, err_msg, alert: true)
138
+ end
139
+
140
+ def ensure_can_be_modified!(sint, c)
141
+ permission_error!("Sorry, you cannot modify this integration.") unless sint.can_be_modified_by?(c)
142
+ end
143
+ end
144
+
145
+ post :setup do
146
+ ensure_plan_supports!
147
+ c = current_customer
148
+ org = lookup_org!
149
+ sint = lookup_service_integration!(org, params[:sint_identifier])
150
+ svc = Webhookdb::Replicator.create(sint)
151
+ merror!(403, "Sorry, you cannot modify this integration.") unless sint.can_be_modified_by?(c)
152
+ state_machine = svc.calculate_preferred_create_state_machine
153
+ status 200
154
+ present state_machine, with: Webhookdb::API::StateMachineEntity
155
+ end
156
+
157
+ post :reset do
158
+ ensure_plan_supports!
159
+ c = current_customer
160
+ org = lookup_org!
161
+ sint = lookup_service_integration!(org, params[:sint_identifier])
162
+ svc = Webhookdb::Replicator.create(sint)
163
+ merror!(403, "Sorry, you cannot modify this integration.") unless sint.can_be_modified_by?(c)
164
+ svc.clear_webhook_information
165
+ state_machine = svc.calculate_preferred_create_state_machine
166
+ status 200
167
+ present state_machine, with: Webhookdb::API::StateMachineEntity
168
+ end
169
+
170
+ post :upsert do
171
+ current_customer
172
+ org = lookup_org!
173
+ sint = lookup_service_integration!(org, params[:sint_identifier])
174
+ svc = Webhookdb::Replicator.create(sint)
175
+ body = env["api.request.body"]
176
+ begin
177
+ svc.upsert_webhook_body(body)
178
+ rescue KeyError, TypeError => e
179
+ self.logger.error "immediate_upsert", error: e
180
+ err_msg = "Sorry! Looks like something has gone wrong. " \
181
+ "Check your schema or contact support at #{Webhookdb.support_email}."
182
+ merror!(400, err_msg)
183
+ end
184
+ status 200
185
+ present({}, with: Webhookdb::API::BaseEntity, message: "You have upserted into #{sint.table_name}.")
186
+ end
187
+
188
+ desc "Returns information about the integration."
189
+ params do
190
+ optional :field, type: String, values: Webhookdb::ServiceIntegration::INTEGRATION_INFO_FIELDS
191
+ end
192
+ post :info do
193
+ ensure_plan_supports!
194
+ org = lookup_org!
195
+ sint = lookup_service_integration!(org, params[:sint_identifier])
196
+ data = {
197
+ id: sint.opaque_id,
198
+ service: sint.service_name,
199
+ table: sint.table_name,
200
+ url: sint.replicator.webhook_endpoint,
201
+ webhook_secret: sint.webhook_secret,
202
+ }
203
+
204
+ field_name = params[:field]
205
+ blocks = Webhookdb::Formatting.blocks
206
+ if field_name.present?
207
+ blocks.line(data.fetch(field_name.to_sym))
208
+ else
209
+ rows = data.map do |k, v|
210
+ [k.to_s.capitalize, v]
211
+ end
212
+ blocks.table(["Field", "Value"], rows)
213
+ end
214
+ r = {blocks: blocks.as_json}
215
+ status 200
216
+ present r
217
+ end
218
+
219
+ resource :backfill do
220
+ helpers do
221
+ def lookup_backfillable_replicator(customer:, allow_connstr_auth: false)
222
+ org = lookup_org!(allow_connstr_auth:)
223
+ ensure_plan_supports!(org)
224
+ sint = lookup_service_integration!(org, params[:sint_identifier])
225
+ ensure_can_be_modified!(sint, customer) if customer
226
+ return sint.replicator
227
+ end
228
+
229
+ def ensure_backfill_supported!(rep)
230
+ return if rep.descriptor.supports_backfill?
231
+ msg = rep.backfill_not_supported_message
232
+ merror!(409, msg)
233
+ end
234
+ end
235
+
236
+ params do
237
+ optional :incremental, type: Boolean
238
+ end
239
+ post do
240
+ rep = lookup_backfillable_replicator(customer: current_customer)
241
+ ensure_backfill_supported!(rep)
242
+ state_machine, _ = rep.calculate_and_backfill_state_machine(incremental: params.fetch(:incremental, true))
243
+ status 200
244
+ present state_machine, with: Webhookdb::API::StateMachineEntity
245
+ end
246
+
247
+ post :reset do
248
+ repl = lookup_backfillable_replicator(customer: current_customer)
249
+ ensure_backfill_supported!(repl)
250
+ state_machine = repl.service_integration.db.transaction do
251
+ repl.clear_backfill_information
252
+ step, _ = repl.calculate_and_backfill_state_machine(incremental: true)
253
+ step
254
+ end
255
+ status 200
256
+ present state_machine, with: Webhookdb::API::StateMachineEntity
257
+ end
258
+
259
+ resource :job do
260
+ params do
261
+ optional :incremental, type: Boolean, default: true
262
+ optional :criteria, type: JSON
263
+ optional :recursive, type: Boolean, default: true
264
+ optional :synchronous, type: Boolean
265
+ end
266
+ post do
267
+ rep = lookup_backfillable_replicator(customer: nil, allow_connstr_auth: true)
268
+ ensure_backfill_supported!(rep)
269
+ sint = rep.service_integration
270
+ incremental = params.fetch(:incremental)
271
+ recursive = params.fetch(:recursive)
272
+ if (synchronous = params[:synchronous] || false)
273
+ invalid!("Recursive backfills cannot be synchronous") if recursive
274
+ invalid!("Only incremental backfills can be synchronous") unless incremental
275
+ unless sint.organization.priority_backfill
276
+ merror!(402,
277
+ "Organization does not support sychronous backfills",
278
+ code: "priority_backfill_not_enabled",)
279
+ end
280
+ end
281
+ _, job = rep.calculate_and_backfill_state_machine(
282
+ incremental:,
283
+ recursive:,
284
+ criteria: params[:criteria] || nil,
285
+ enqueue: !synchronous,
286
+ )
287
+ if job.nil?
288
+ msg = "Sorry, this integration is not set up to backfill. " \
289
+ "Run `webhookdb backfill #{sint.opaque_id}` to finish setup."
290
+ merror!(409, msg, code: "backfill_not_set_up")
291
+ end
292
+ sint.replicator.backfill(job) if synchronous
293
+ status 200
294
+ present job, with: Webhookdb::API::BackfillJobEntity
295
+ end
296
+
297
+ route_param :job_id, type: String do
298
+ get do
299
+ org = lookup_org!(allow_connstr_auth: true)
300
+ job = Webhookdb::BackfillJob[service_integration: org.service_integrations_dataset,
301
+ opaque_id: params[:job_id]]
302
+ forbidden! if job.nil?
303
+ present job, with: Webhookdb::API::BackfillJobEntity
304
+ end
305
+ end
306
+ end
307
+ end
308
+
309
+ resource :transition do
310
+ route_param :field do
311
+ params do
312
+ requires :value
313
+ end
314
+ post do
315
+ ensure_plan_supports!
316
+ c = current_customer
317
+ org = lookup_org!
318
+ sint = lookup_service_integration!(org, params[:sint_identifier])
319
+ ensure_can_be_modified!(sint, c)
320
+ state_machine = sint.replicator.process_state_change(params[:field], params[:value])
321
+ status 200
322
+ present state_machine, with: Webhookdb::API::StateMachineEntity
323
+ end
324
+ end
325
+ end
326
+
327
+ desc "Gets stats about webhooks for this service integration."
328
+ get :stats do
329
+ org = lookup_org!
330
+ sint = lookup_service_integration!(org, params[:sint_identifier])
331
+ stats = sint.stats
332
+ status 200
333
+ present stats.as_json
334
+ end
335
+
336
+ params do
337
+ optional :confirm, type: String
338
+ end
339
+ post :delete do
340
+ ensure_plan_supports!
341
+ ensure_admin!
342
+ org = lookup_org!
343
+ sint = lookup_service_integration!(org, params[:sint_identifier])
344
+ dependents_lines = sint.recursive_dependents.map(&:table_name).join("\n")
345
+ if sint.table_name != params[:confirm]&.strip
346
+ output = if sint.dependents.empty?
347
+ "Please confirm your deletion by entering the integration's table name '" \
348
+ "#{sint.table_name}'. The table and all data for this integration will also be removed."
349
+ else
350
+ %(This integration has dependents and therefore cannot be deleted on its own.
351
+ If you choose to go forward with the deletion, WebhookDB will recursively delete all dependents.
352
+ For reference, this includes the following integrations:
353
+
354
+ #{dependents_lines}
355
+
356
+ Please confirm your deletion by entering the integration's table name '#{sint.table_name}'.
357
+ The tables and all data for this integration and its dependents will also be removed:)
358
+ end
359
+ Webhookdb::API::Helpers.prompt_for_required_param!(
360
+ request,
361
+ :confirm,
362
+ "Confirm table name '#{sint.table_name}':",
363
+ output:,
364
+ )
365
+ end
366
+
367
+ sint.destroy_self_and_all_dependents
368
+ status 200
369
+
370
+ if sint.dependents.empty?
371
+ confirmation_msg = "Great! We've deleted all secrets for #{sint.service_name}. " \
372
+ "The table #{sint.table_name} containing its data has been dropped."
373
+ else
374
+ confirmation_msg = "Great! We've deleted all secrets for #{sint.service_name} and its dependents. " \
375
+ "The following tables have been dropped: \n\n #{sint.table_name} \n #{dependents_lines}"
376
+ end
377
+ present sint, with: Webhookdb::API::ServiceIntegrationEntity, message: confirmation_msg
378
+ end
379
+
380
+ params do
381
+ optional :new_name,
382
+ type: String,
383
+ db_identifier: true,
384
+ prompt: "Enter the new name of the table. " + Webhookdb::DBAdapter::INVALID_IDENTIFIER_MESSAGE
385
+ end
386
+ post :rename_table do
387
+ org = lookup_org!
388
+ sint = lookup_service_integration!(org, params[:sint_identifier])
389
+ ensure_admin!
390
+ old_name = sint.table_name
391
+ sint.db.transaction do
392
+ sint.rename_table(to: params[:new_name])
393
+ message = "The table for #{sint.service_name} has been renamed from #{old_name} to #{sint.table_name}."
394
+ status 200
395
+ present sint, with: Webhookdb::API::ServiceIntegrationEntity, message:
396
+ end
397
+ end
398
+ end
399
+ end
400
+ end
401
+ end
402
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb/api"
6
+ require "webhookdb/replicator"
7
+
8
+ class Webhookdb::API::Services < Webhookdb::API::V1
9
+ resource :services do
10
+ route_param :service_name, type: String do
11
+ get :fixtures do
12
+ begin
13
+ descr = Webhookdb::Replicator.registered!(params[:service_name])
14
+ rescue Webhookdb::Replicator::Invalid
15
+ merror!(403, "No service with that name exists.")
16
+ end
17
+ sint = Webhookdb::ServiceIntegration.new(
18
+ service_name: params[:service_name],
19
+ opaque_id: "svi_fixture",
20
+ table_name: params[:service_name] + "_fixture",
21
+ )
22
+ sch = descr.ctor.call(sint).create_table_modification.to_s
23
+ present({schema_sql: sch})
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/stripe"
4
+ require "webhookdb/api"
5
+
6
+ class Webhookdb::API::Stripe < Webhookdb::API::V1
7
+ resource :stripe do
8
+ resource :webhook do
9
+ post do
10
+ whresp = Webhookdb::Stripe.webhook_response(request, Webhookdb::Stripe.webhook_secret)
11
+ s_status, s_headers, s_body = whresp.to_rack
12
+ if s_status < 400 && request.params["data"]["object"]["object"] == "subscription"
13
+ Webhookdb::Subscription.create_or_update_from_webhook(request.params)
14
+ end
15
+ env["warden"].custom_failure!
16
+ s_headers.each { |k, v| header k, v }
17
+ body s_body
18
+ status s_status
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb/api"
6
+ require "webhookdb/admin_api"
7
+
8
+ class Webhookdb::API::Subscriptions < Webhookdb::API::V1
9
+ resource :organizations do
10
+ route_param :org_identifier, type: String do
11
+ resource :subscriptions do
12
+ desc "Provides the user with subscription information for the organization"
13
+ get do
14
+ org = lookup_org!
15
+ status = Webhookdb::Subscription.status_for_org(org)
16
+ status 200
17
+ present status.as_json
18
+ end
19
+
20
+ desc "Authenticates stripe user and returns stripe checkout session or billing portal url"
21
+ params do
22
+ optional :plan, type: String
23
+ optional :guard_confirm
24
+ end
25
+ post :open_portal do
26
+ org = lookup_org!
27
+ merror!(409, "This organization is not registered with Stripe.", alert: true) if org.stripe_customer_id.blank?
28
+ subscription = Webhookdb::Subscription[stripe_customer_id: org.stripe_customer_id]
29
+ if subscription
30
+ if params[:plan] && !params.key?(:guard_confirm)
31
+ Webhookdb::API::Helpers.prompt_for_required_param!(
32
+ request,
33
+ :guard_confirm,
34
+ "WARNING: You already have a subscription, but have specified a plan.\n" \
35
+ "You will be brought to your subscription so you can modify or cancel it.\n" \
36
+ "Press Enter to continue:",
37
+ )
38
+ end
39
+ session_url = org.get_stripe_billing_portal_url
40
+ else
41
+ plans = Webhookdb::Subscription.list_plans
42
+ real_plan = plans.find { |p| p.key == params[:plan] }
43
+ unless real_plan
44
+ Webhookdb::API::Helpers.prompt_for_required_param!(
45
+ request,
46
+ :plan,
47
+ "Available plans: #{plans.map(&:key).join(', ')}\nEnter the plan you want to subscribe to:",
48
+ )
49
+ end
50
+ session_url = org.get_stripe_checkout_url(real_plan.stripe_price_id)
51
+ end
52
+ data = {url: session_url}
53
+ status 200
54
+ present data
55
+ end
56
+
57
+ desc "Returns information about subscription plans"
58
+ get :plans do
59
+ plans = Webhookdb::Subscription.list_plans
60
+ message = "Use `webhookdb subscription edit` to set up or modify your subscription."
61
+ status 200
62
+ present_collection plans, with: Webhookdb::API::SubscriptionPlanEntity, message:
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end