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,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb/admin_api"
6
+
7
+ class Webhookdb::AdminAPI::DatabaseDocuments < Webhookdb::AdminAPI::V1
8
+ resource :database_documents do
9
+ route_param :id, type: Integer do
10
+ auth(:skip)
11
+ get :view do
12
+ (doc = Webhookdb::DatabaseDocument[params[:id]]) or forbidden!
13
+ doc.check_url(request.url) or forbidden!
14
+ content_type doc.content_type
15
+ env["api.format"] = :binary
16
+ body doc.content
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape_entity"
4
+
5
+ require "webhookdb/service/entities"
6
+ require "webhookdb/admin_api" unless defined? Webhookdb::AdminAPI
7
+
8
+ module Webhookdb::AdminAPI
9
+ CurrentCustomerEntity = Webhookdb::Service::Entities::CurrentCustomer
10
+ MoneyEntity = Webhookdb::Service::Entities::Money
11
+ TimeRangeEntity = Webhookdb::Service::Entities::TimeRange
12
+
13
+ class BaseEntity < Webhookdb::Service::Entities::Base; end
14
+
15
+ class RoleEntity < BaseEntity
16
+ expose :id
17
+ expose :name
18
+ end
19
+
20
+ class CustomerEntity < BaseEntity
21
+ expose :id
22
+ expose :created_at
23
+ expose :email
24
+ expose :name
25
+ expose :note
26
+ end
27
+
28
+ class CustomerResetCodes < BaseEntity
29
+ expose :id
30
+ expose :created_at
31
+ expose :transport
32
+ expose :token
33
+ expose :used
34
+ expose :expire_at
35
+ end
36
+
37
+ class DetailedCustomerEntity < CustomerEntity
38
+ expose :roles do |instance|
39
+ instance.roles.map(&:name)
40
+ end
41
+ expose :reset_codes, with: CustomerResetCodes
42
+ end
43
+
44
+ class MessageBodyEntity < BaseEntity
45
+ expose :id
46
+ expose :content
47
+ expose :mediatype
48
+ end
49
+
50
+ class MessageDeliveryEntity < BaseEntity
51
+ expose :id
52
+ expose :created_at
53
+ expose :updated_at
54
+ expose :soft_deleted_at
55
+ expose :template
56
+ expose :transport_type
57
+ expose :transport_service
58
+ expose :transport_message_id
59
+ expose :sent_at
60
+ expose :to
61
+ end
62
+
63
+ class MessageDeliveryWithBodiesEntity < MessageDeliveryEntity
64
+ expose :bodies, with: MessageBodyEntity
65
+ end
66
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb/admin_api"
6
+
7
+ class Webhookdb::AdminAPI::MessageDeliveries < Webhookdb::AdminAPI::V1
8
+ helpers do
9
+ def lookup_delivery(params)
10
+ (batch = Webhookdb::Message::Delivery[params[:id]]) or not_found!
11
+ return batch
12
+ end
13
+ end
14
+
15
+ resource :message_deliveries do
16
+ desc "Return all message deliveries, newest first"
17
+ params do
18
+ use :pagination
19
+ use :ordering, model: Webhookdb::Message::Delivery
20
+ use :searchable
21
+ end
22
+ get do
23
+ ds = Webhookdb::Message::Delivery.dataset
24
+ if (to_like = search_param_to_sql(params, :to))
25
+ criteria = to_like | search_param_to_sql(params, :template)
26
+ ds = ds.where(criteria)
27
+ end
28
+ ds = order(ds, params)
29
+ ds = paginate(ds, params)
30
+ present_collection ds, with: Webhookdb::AdminAPI::MessageDeliveryEntity
31
+ end
32
+
33
+ desc "Return the delivery with the last ID"
34
+ get :last do
35
+ delivery = Webhookdb::Message::Delivery.last
36
+ present delivery, with: Webhookdb::AdminAPI::MessageDeliveryWithBodiesEntity
37
+ end
38
+
39
+ route_param :id, type: Integer do
40
+ desc "Return the delivery"
41
+ get do
42
+ delivery = lookup_delivery(params)
43
+ present delivery, with: Webhookdb::AdminAPI::MessageDeliveryWithBodiesEntity
44
+ end
45
+ end
46
+ end
47
+
48
+ resource :customers do
49
+ route_param :id, type: Integer do
50
+ resource :message_deliveries do
51
+ desc "Return all message deliveries for customer the given customers, as recipients or to their emails"
52
+ get do
53
+ # rubocop:disable Layout/LineLength
54
+ ds = Webhookdb::Message::Delivery.to_customers(Webhookdb::Customer.where(id: params[:id])).order(Sequel.desc(:id))
55
+ # rubocop:enable Layout/LineLength
56
+ present_collection ds, with: Webhookdb::AdminAPI::MessageDeliveryEntity
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb/admin_api"
6
+
7
+ class Webhookdb::AdminAPI::Roles < Webhookdb::AdminAPI::V1
8
+ resource :roles do
9
+ desc "Return all roles, ordered by name"
10
+ get do
11
+ ds = Webhookdb::Role.dataset.order(:name)
12
+ present_collection ds, with: Webhookdb::AdminAPI::RoleEntity
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb"
6
+ require "webhookdb/service"
7
+
8
+ # API is the namespace module for Admin API resources.
9
+ module Webhookdb::AdminAPI
10
+ require "webhookdb/admin_api/entities"
11
+
12
+ class V1 < Webhookdb::Service
13
+ def self.inherited(subclass)
14
+ super
15
+ subclass.instance_eval do
16
+ version "v1", using: :path
17
+ format :json
18
+
19
+ content_type :csv, "text/csv"
20
+
21
+ require "webhookdb/service/helpers"
22
+ helpers Webhookdb::Service::Helpers
23
+
24
+ auth(:admin)
25
+
26
+ before do
27
+ Sentry.configure_scope do |scope|
28
+ scope.set_tags(application: "admin-api")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb" unless defined?(Webhookdb)
4
+
5
+ # Value returned or raised from a method that deals with aggregate success or failure.
6
+ #
7
+ # Sometimes we want to process a collection of items,
8
+ # and not fail the entire thing if some fail. In this case, we can return an AggregateResult.
9
+ # If the AggregateResult is returned, we know all items processed.
10
+ # If it is raised, at least some of the items errored.
11
+ #
12
+ # Example:
13
+ # ag = AggregateResult.new
14
+ # items.each do |item|
15
+ # ag.success(myfunc(item))
16
+ # rescue => e
17
+ # ag.failure(item, e)
18
+ # end
19
+ # return ag.finish
20
+ #
21
+ class Webhookdb::AggregateResult < StandardError
22
+ attr_reader :successes, :failures, :errors
23
+
24
+ def initialize(existing=nil)
25
+ if existing.nil?
26
+ @successes = []
27
+ @failures = []
28
+ @errors = []
29
+ super("awaiting result")
30
+ return
31
+ end
32
+ # We can only set the exception message from initialization
33
+ @successes = existing.successes
34
+ @failures = existing.failures
35
+ @errors = existing.errors
36
+ if @failures.empty?
37
+ super("No errors")
38
+ return
39
+ end
40
+
41
+ lines = ["Multiple errors occurred:"]
42
+ @failures.each_with_index do |f, i|
43
+ lines << " #{f.inspect}: #{@errors[i].message}"
44
+ end
45
+ super(lines.join("\n"))
46
+ end
47
+
48
+ def success(i)
49
+ @successes << i
50
+ end
51
+
52
+ def failure(i, e)
53
+ @failures << i
54
+ @errors << e
55
+ end
56
+
57
+ def finish
58
+ raise InvalidPrecondition, "failures.length must equal errors.length" unless @failures.length == @errors.length
59
+ result = Webhookdb::AggregateResult.new(self)
60
+ return result if self.failures.empty?
61
+ raise result
62
+ end
63
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/api"
4
+ require "webhookdb/demo_mode"
5
+
6
+ class Webhookdb::API::Auth < Webhookdb::API::V1
7
+ include Webhookdb::Service::Types
8
+
9
+ resource :auth do
10
+ helpers do
11
+ def guard_logged_in!
12
+ c = current_customer?
13
+ return if c.nil?
14
+ merror!(403, "You are already logged in as #{c.email}. You must log out first.", code: "already_logged_in")
15
+ end
16
+ end
17
+
18
+ helpers do
19
+ def finish_auth(me)
20
+ set_customer(me) if me
21
+ extras = {}
22
+ extras[:current_customer] = Webhookdb::API::CurrentCustomerEntity.represent(me).as_json if me
23
+ return extras
24
+ end
25
+ end
26
+
27
+ params do
28
+ optional :email,
29
+ type: String,
30
+ coerce_with: NormalizedEmail,
31
+ prompt: {
32
+ message: "Welcome to WebhookDB!\nPlease enter your email:",
33
+ demo_mode_proc: ->(r) { r.params[:email] = "demo@webhookdb.com" },
34
+ }
35
+ optional :token, type: String
36
+ end
37
+ post do
38
+ message = ""
39
+ if Webhookdb::DemoMode.client_enabled?
40
+ membership, step, message = Webhookdb::DemoMode.handle_auth
41
+ me = membership.customer
42
+ extras = finish_auth(me)
43
+ status 200
44
+ elsif params[:token].blank?
45
+ guard_logged_in!
46
+ begin
47
+ step, _ = Webhookdb::Customer.register_or_login(email: params[:email])
48
+ rescue Webhookdb::Customer::SignupDisabled
49
+ merror!(402, "Sorry, new signups are currently disabled.", code: "signup_disabled")
50
+ end
51
+ extras = {}
52
+ status 202
53
+ else
54
+ guard_logged_in!
55
+ step, me = Webhookdb::Customer.finish_otp(
56
+ Webhookdb::Customer[email: params[:email]], token: params[:token],
57
+ )
58
+ extras = finish_auth(me)
59
+ status 200
60
+ end
61
+ present step, with: Webhookdb::API::StateMachineEntity, extras:, message:
62
+ end
63
+
64
+ resource :login_otp do
65
+ route_param :opaque_id do
66
+ desc "Verify the OTP and auth the customer"
67
+ params do
68
+ requires :value
69
+ end
70
+ post do
71
+ guard_logged_in!
72
+ step, me = Webhookdb::Customer.finish_otp(
73
+ Webhookdb::Customer[opaque_id: params[:opaque_id]], token: params[:value],
74
+ )
75
+ extras = finish_auth(me)
76
+ status 200
77
+ present step, with: Webhookdb::API::StateMachineEntity, extras:
78
+ end
79
+ end
80
+ end
81
+
82
+ post :logout do
83
+ delete_session_cookies
84
+ status 200
85
+ present({}, with: Webhookdb::API::BaseEntity, message: "You have logged out.")
86
+ end
87
+
88
+ params do
89
+ requires :form_name, type: String
90
+ optional :email, type: String
91
+ optional :name, type: String
92
+ optional :message, type: String
93
+ end
94
+ post :contact do
95
+ fields = []
96
+ fields << {title: "Form", value: params[:form_name], short: true}
97
+ fields << {title: "IP", value: request.ip, short: true}
98
+ fields << {title: "User Agent", value: request.user_agent || "", short: false}
99
+ if (email = params[:email])
100
+ fields << {title: "Email", value: email, short: true}
101
+ end
102
+ if (name = params[:name])
103
+ fields << {title: "Name", value: name, short: true}
104
+ end
105
+ if (msg = params[:message])
106
+ fields << {title: "Message", value: msg, short: false}
107
+ end
108
+
109
+ Webhookdb::DeveloperAlert.new(
110
+ subsystem: "New Contact",
111
+ emoji: ":mailbox_with_mail:",
112
+ fallback: fields.
113
+ map { |f| "#{f[:title]}: #{f[:value]}" }.
114
+ join(", "),
115
+ fields:,
116
+ ).emit
117
+
118
+ status 200
119
+ present({message: "ok"})
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ # Some routes allow the SHA256 hash hexdigest connection string
6
+ # to be used in place of normal authentication (for example, queries to the database,
7
+ # which are not tied to a user). Do NOT extract this automatically (like org_identifier)
8
+ # since we want endpoints to specify that they use the param explicitly.
9
+ module Webhookdb::API::ConnstrAuth
10
+ ALGOS = ["Sha256"].freeze
11
+
12
+ def self.headers_desc
13
+ return ALGOS.to_h do |algo|
14
+ h = {
15
+ required: false,
16
+ algo:,
17
+ description: "Hex digest of the #{algo} hash of the organization connection string, " \
18
+ "like Ruby's Digest::#{algo.upcase}.hexdigest(conn_str). " \
19
+ "Can be used in place of normal auth.",
20
+ }
21
+ ["Whdb-#{algo}-Conn", h]
22
+ end
23
+ end
24
+
25
+ def self.find_authed(orgs, request)
26
+ orgs.find do |o|
27
+ self.headers_desc.each do |header_name, desc|
28
+ header_value = request.headers[header_name]
29
+ next if header_value.blank?
30
+ org_value = Digest.const_get(desc.fetch(:algo).upcase.to_sym).send(:hexdigest, o.readonly_connection_url)
31
+ return o if header_value == org_value
32
+ end
33
+ end
34
+ return nil
35
+ end
36
+ end
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "grape"
4
+
5
+ require "webhookdb/api"
6
+ require "webhookdb/replicator"
7
+
8
+ class Webhookdb::API::Db < Webhookdb::API::V1
9
+ helpers do
10
+ params :fdw do
11
+ optional :message_fdw, type: Boolean
12
+ optional :message_views, type: Boolean
13
+ optional :message_all, type: Boolean
14
+ requires :remote_server_name, type: String
15
+ requires :fetch_size, type: String
16
+ requires :local_schema, type: String
17
+ requires :view_schema, type: String
18
+ end
19
+
20
+ def run_fdw
21
+ org = lookup_org!
22
+ resp = Webhookdb::Organization::DbBuilder.new(org).generate_fdw_payload(
23
+ remote_server_name: params[:remote_server_name],
24
+ fetch_size: params[:fetch_size],
25
+ local_schema: params[:local_schema],
26
+ view_schema: params[:view_schema],
27
+ )
28
+ resp[:message] = if params[:message_fdw]
29
+ resp[:fdw_sql]
30
+ elsif params[:message_views]
31
+ resp[:views_sql]
32
+ else
33
+ resp[:compound_sql]
34
+ end
35
+ status 200
36
+ present resp
37
+ end
38
+ end
39
+
40
+ resource :db do
41
+ route_param :org_identifier, type: String do
42
+ desc "Returns the connection string"
43
+ get :connection do
44
+ _customer = current_customer
45
+ org = lookup_org!
46
+ r = {connection_url: org.readonly_connection_url}
47
+ present r
48
+ end
49
+
50
+ desc "Returns a list of all tables in the organization's db."
51
+ get :tables do
52
+ _customer = current_customer
53
+ org = lookup_org!
54
+ tables = org.readonly_connection do |db|
55
+ db.tables(schema: org.replication_schema)
56
+ end
57
+ message = ""
58
+ if tables.empty?
59
+ message = "You have not set up any service integrations.\n" \
60
+ "Use `webhookdb services list` and `webhookdb integrations create` to get started."
61
+ end
62
+ present({tables:, message:})
63
+ end
64
+
65
+ desc "Enqueues a database migration."
66
+ params do
67
+ optional :admin_url, type: String, prompt: {
68
+ message: "ADMIN Postgres connection URL, in the form 'postgres://user:password@host:port/dbname',\n" \
69
+ "that is capable of administrative operations on your database,\n" \
70
+ "such as creating and dropping schemas and tables.\n" \
71
+ "Input ADMIN URL, then press Enter:",
72
+ secret: true,
73
+ disable: ->(_) { !Webhookdb::Organization::DbBuilder.allow_public_migrations },
74
+ }
75
+
76
+ optional :readonly_url, type: String, prompt: {
77
+ message: "READONLY Postgres connection URL.\n" \
78
+ "This string is displayed when you ask for your organization's connection information.\n" \
79
+ "If you are okay with this being your ADMIN URL, leave it blank.\n" \
80
+ "Input READONLY URL, or leave blank, then press Enter:",
81
+ secret: true,
82
+ optional: true,
83
+ disable: ->(_) { !Webhookdb::Organization::DbBuilder.allow_public_migrations },
84
+ }
85
+ end
86
+ post :migrate_database do
87
+ unless Webhookdb::Organization::DbBuilder.allow_public_migrations
88
+ merror!(403,
89
+ "Public database migrations are not enabled. Email #{Webhookdb.oss_repo_url} for more information.",
90
+ code: "migrations_disabled",
91
+ alert: true,)
92
+ end
93
+ ensure_admin!
94
+ org = lookup_org!
95
+ # if the readonly url is blank, default to the admin url
96
+ readonly_url = params[:readonly_url].blank? ? params[:admin_url] : params[:readonly_url]
97
+ dbm = Webhookdb::Organization::DatabaseMigration.enqueue(
98
+ admin_connection_url_raw: params[:admin_url],
99
+ readonly_connection_url_raw: readonly_url,
100
+ public_host: "",
101
+ started_by: current_customer,
102
+ organization: org,
103
+ )
104
+ message = "Your database migration has been enqueued. You'll recieve an email when it is complete."
105
+ status 200
106
+ present dbm, with: Webhookdb::API::DatabaseMigrationEntity, message:
107
+ end
108
+
109
+ desc "Gets list of database migrations for org."
110
+ get :migrations do
111
+ org = lookup_org!
112
+ dbms = org.database_migrations
113
+ message = ""
114
+ message = "Organization #{org.name} has no database migrations" if dbms.empty?
115
+ status 200
116
+ present_collection dbms, with: Webhookdb::API::DatabaseMigrationEntity, message:
117
+ end
118
+
119
+ desc "Execute an arbitrary query against an org's connection string" do
120
+ headers Webhookdb::API::ConnstrAuth.headers_desc
121
+ end
122
+ params do
123
+ optional :query, type: String, prompt: "Input your SQL query, and then press Enter:"
124
+ end
125
+ post :sql do
126
+ org = lookup_org!(allow_connstr_auth: true)
127
+ begin
128
+ r = org.execute_readonly_query(params[:query])
129
+ rescue Sequel::DatabaseError => e
130
+ self.logger.error("db_query_database_error", error: e)
131
+ # We want to handle InsufficientPrivileges and UndefinedTable explicitly
132
+ # since we can hint the user at what to do.
133
+ # Otherwise, we should just return the Postgres exception.
134
+ case e.wrapped_exception
135
+ when PG::UndefinedTable
136
+ missing_table = e.wrapped_exception.message.match(/relation (.+) does not/)&.captures&.first
137
+ msg = "The table #{missing_table} does not exist. Run `webhookdb db tables` to see available tables." if
138
+ missing_table
139
+ when PG::InsufficientPrivilege
140
+ msg = "You do not have permission to perform this query. Queries must be read-only."
141
+ else
142
+ msg = e.wrapped_exception.message
143
+ end
144
+ merror!(403, msg, code: "invalid_query")
145
+ end
146
+ status 200
147
+ present({rows: r.rows, headers: r.columns, max_rows_reached: r.max_rows_reached})
148
+ end
149
+
150
+ params do
151
+ optional :guard_confirm, prompt: {
152
+ message: "WARNING: This will invalidate your existing database credentials. " \
153
+ "Enter to proceed, or Ctrl+C to quit:",
154
+ confirm: true,
155
+ }
156
+ end
157
+ post :roll_credentials do
158
+ ensure_admin!
159
+ org = lookup_org!
160
+ org.roll_database_credentials
161
+ connection_url = org.readonly_connection_url
162
+ status 200
163
+ present(
164
+ {connection_url:},
165
+ with: Webhookdb::API::BaseEntity,
166
+ message: "Your database connection string is now: #{connection_url}",
167
+ )
168
+ end
169
+
170
+ params do
171
+ use :fdw
172
+ end
173
+ post :fdw do
174
+ run_fdw
175
+ end
176
+ end
177
+ end
178
+
179
+ resource :organizations do
180
+ route_param :org_identifier, type: String do
181
+ # See https://github.com/webhookdb/webhookdb/issues/286
182
+ desc "DEPRECATED: Use /v1/db/:key/fdw instead"
183
+ post :fdw do
184
+ run_fdw
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/api"
4
+
5
+ class Webhookdb::API::Demo < Webhookdb::API::V1
6
+ resource :demo do
7
+ post :data do
8
+ merror!(403, "Demo mode is not enabled") unless Webhookdb::DemoMode.server_enabled?
9
+ r = Webhookdb::DemoMode.build_demo_data
10
+ status 200
11
+ present(r)
12
+ end
13
+ end
14
+ end