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,432 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/json"
4
+ require "appydays/loggable"
5
+ require "pathname"
6
+ require "rack/test"
7
+ require "rspec"
8
+ require "warden"
9
+
10
+ require "webhookdb/spec_helpers"
11
+
12
+ module Webhookdb::SpecHelpers::Service
13
+ def self.included(context)
14
+ context.include(WebhookdbTestMethods)
15
+
16
+ ::Warden.test_mode!
17
+
18
+ super
19
+
20
+ context.after(:each) { Warden.test_reset! }
21
+ end
22
+
23
+ def last_session_id
24
+ (set_cookie = last_response["Set-Cookie"]) or return nil
25
+ (session = Webhookdb::Service.decode_cookie(set_cookie)) or return nil
26
+ return session["session_id"]
27
+ end
28
+
29
+ def login_as(customer, opts=nil)
30
+ opts ||= {scope: :customer}
31
+ Warden.on_next_request do |proxy|
32
+ opts[:event] ||= :authentication
33
+ proxy.set_user(customer, opts)
34
+ end
35
+ end
36
+
37
+ def login_as_admin(customer, opts={})
38
+ login_as(customer, opts.merge(scope: :customer))
39
+ login_as(customer, opts.merge(scope: :admin))
40
+ end
41
+
42
+ def impersonate(admin: nil, target: nil)
43
+ admin ||= Webhookdb::Fixtures.customer.admin.create
44
+ target ||= Webhookdb::Fixtures.customer.create
45
+ Warden.on_next_request do |proxy|
46
+ proxy.set_user(admin, event: :authentication, scope: :admin)
47
+ proxy.set_user(target, event: :authentication, scope: :customer)
48
+ Webhookdb::Service::Auth::Impersonation.new(proxy).on(target)
49
+ end
50
+ end
51
+
52
+ def logout(*scopes)
53
+ Warden.on_next_request do |proxy|
54
+ proxy.logout(*scopes)
55
+ end
56
+ end
57
+
58
+ def fake_request(input: "", env: {})
59
+ req = Rack::Request.new(env.merge({"rack.input" => Rewindable.new(input)}))
60
+ return req
61
+ end
62
+
63
+ class Rewindable < String
64
+ def initialize(s)
65
+ super
66
+ @s = s
67
+ end
68
+
69
+ def read(*)
70
+ return @s
71
+ end
72
+
73
+ def rewind(*)
74
+ nil
75
+ end
76
+ end
77
+
78
+ class FakeSentryScope
79
+ attr_accessor :user, :tags
80
+
81
+ def initialize
82
+ @user = {}
83
+ @tags = {}
84
+ end
85
+
86
+ def set_user(user)
87
+ @user.merge!(user)
88
+ end
89
+
90
+ def set_tags(tags)
91
+ @tags.merge!(tags)
92
+ end
93
+ end
94
+
95
+ # RSpec matcher for matching Rack::Test response body
96
+ #
97
+ # Expect that the response consists of JSON of some sort:
98
+ #
99
+ # expect( last_response ).to have_json_body
100
+ #
101
+ # Expect that it's a JSON body that deserializes as an Object:
102
+ #
103
+ # expect( last_response ).to have_json_body( Object )
104
+ # # -or-
105
+ # expect( last_response ).to have_json_body( Hash )
106
+ #
107
+ # Expect that it's a JSON body that deserializes as an Array:
108
+ #
109
+ # expect( last_response ).to have_json_body( Array )
110
+ #
111
+ # Expect that it's a JSON body that deserializes as an Object that has
112
+ # expected keys:
113
+ #
114
+ # expect( last_response ).to have_json_body( Object ).
115
+ # that_includes( :id, :first_name, :last_name )
116
+ #
117
+ # Expect that it's a JSON body that deserializes as an Object that has
118
+ # expected keys and values:
119
+ #
120
+ # expect( last_response ).to have_json_body( Object ).
121
+ # that_includes(
122
+ # id: 118,
123
+ # first_name: 'Princess',
124
+ # last_name: 'Buttercup'
125
+ # )
126
+ #
127
+ # Expect that it's a JSON body that has other expected stuff:
128
+ #
129
+ # expect( last_response ).to have_json_body( Object ).
130
+ # that_includes(
131
+ # last_name: a_string_matching(/humperdink/i),
132
+ # profile: a_hash_including(:age, :eyecolor, :tracking_ability)
133
+ # )
134
+ #
135
+ # Expect a JSON Array with objects that all match the criteria:
136
+ #
137
+ # expect( last_response ).to have_json_body( Array ).
138
+ # of_lenth( 20 ).
139
+ # and( all( be_an(Integer) ) )
140
+ #
141
+ class HaveJSONBodyMatcher
142
+ include Appydays::Loggable
143
+ include RSpec::Matchers
144
+
145
+ ### Create a new matcher that expects a response with a JSON body. If +expected_type+
146
+ ### is not specified, any JSON body will be sufficient for a match.
147
+ def initialize(expected_type=nil)
148
+ @expected_type = expected_type
149
+ @additional_expectations = []
150
+ @response = nil
151
+ @failure_description = nil
152
+ end
153
+
154
+ attr_reader :expected_type,
155
+ :additional_expectations,
156
+ :response,
157
+ :failure_description
158
+
159
+ ### RSpec matcher API -- returns +true+ if all expectations of the specified
160
+ ### +response+ are met.
161
+ def matches?(response)
162
+ @response = response
163
+ return self.correct_content_type? &&
164
+ self.correct_json_type? &&
165
+ self.matches_additional_expectations?
166
+ rescue StandardError => e
167
+ return self.fail_with "Response has invalid JSON body: %s: %s" % [e.class.name, e.message]
168
+ end
169
+
170
+ ### RSpec matcher API -- return a message describing an expectation failure.
171
+ def failure_message
172
+ return "\n---\n%s\n---\n\nReason: %s\n" % [
173
+ self.pretty_print_response,
174
+ self.failure_description,
175
+ ]
176
+ end
177
+
178
+ ### RSpec matcher API -- return a message describing an expectation being met
179
+ ### when the matcher was used in a negated context.
180
+ def failure_message_when_negated
181
+ msg = "expected response not to have a %s" % [self.describe_type_expectation]
182
+ msg << " and " << self.describe_additional_expectations.join(", ") unless
183
+ self.additional_expectations.emtpy?
184
+ msg << ", but it did."
185
+
186
+ return "\n---\n%s\n---\n\nReason: %s\n" % [
187
+ self.pretty_print_response,
188
+ msg,
189
+ ]
190
+ end
191
+
192
+ ### Return the response's body parsed as JSON.
193
+ def parsed_response_body
194
+ return @parsed_response_body ||= JSON.parse(self.response.body, symbolize_names: true)
195
+ end
196
+
197
+ #
198
+ # Mutators
199
+ #
200
+
201
+ ### Add an additional expectation that the JSON body contains the specified +members+.
202
+ def that_includes(*memberset)
203
+ @additional_expectations << include(*memberset)
204
+ return self
205
+ end
206
+ alias which_includes that_includes
207
+
208
+ ### Add an additional expectation that the JSON body does not contain the
209
+ ### specified +members+.
210
+ def that_excludes(*memberset)
211
+ @additional_expectations << exclude(*memberset)
212
+ return self
213
+ end
214
+
215
+ ### Add an additional expectation that the JSON body contain the specified
216
+ ### +number+ of members.
217
+ def of_length(number)
218
+ @additional_expectations << have_attributes(length: number)
219
+ return self
220
+ end
221
+ alias of_size of_length
222
+
223
+ ### Add the specified +matchers+ as expectations of the Hash or Array that's
224
+ ### parsed from the JSON body.
225
+ def and(*matchers)
226
+ @additional_expectations.concat(matchers)
227
+ return self
228
+ end
229
+
230
+ ### Return a String that contains a pretty-printed version of the response object.
231
+ protected def pretty_print_response
232
+ return "%d %s HTTP/1.1\n%s\n\n%s" % [
233
+ self.response.status,
234
+ Rack::Utils::HTTP_STATUS_CODES[self.response.status],
235
+ self.pretty_print_response_headers,
236
+ self.pretty_print_response_body.encode("utf-8", invalid: :replace, undef: :replace),
237
+ ]
238
+ end
239
+
240
+ ### Return a String that contains a pretty-printed version of the response headers.
241
+ protected def pretty_print_response_headers
242
+ s = self.response.headers.map do |name, val|
243
+ "%s: %s" % [name, val]
244
+ end.join("\n")
245
+ return s
246
+ end
247
+
248
+ ### Return a String that contains a pretty-printed version of the response body.
249
+ protected def pretty_print_response_body
250
+ return Webhookdb::Json.pretty_generate(@parsed_response_body) if
251
+ @parsed_response_body
252
+
253
+ data = self.response.body
254
+ return data ? data[0, 1000] : "(empty body)"
255
+ end
256
+
257
+ ### Return +false+ after setting the failure message to +message+.
258
+ protected def fail_with(message)
259
+ @failure_description = message
260
+ self.logger.error "Failing with: %s" % [message]
261
+ return false
262
+ end
263
+
264
+ ### Returns +true+ if the response has a JSON content-type header.
265
+ protected def correct_content_type?
266
+ content_type = self.response["content-type"]
267
+ return self.fail_with "response doesn't have a Content-type header" unless content_type
268
+
269
+ return fail_with "response's Content-type is %p" % [content_type] unless
270
+ content_type.start_with?("application/json")
271
+
272
+ return true
273
+ end
274
+
275
+ ### Return an Array of text describing the expectation that the body be an
276
+ ### Object or an Array, if a type was expected. If no type was expected, returns
277
+ ### an empty Array.
278
+ protected def describe_type_expectation
279
+ return case self.expected_type
280
+ when Object, Hash
281
+ "a JSON Object/Hash body"
282
+ when Array
283
+ "a JSON Array body"
284
+ else
285
+ "a JSON body"
286
+ end
287
+ end
288
+
289
+ ### Check that the JSON body of the response has the correct type, if a type
290
+ ### was specified.
291
+ protected def correct_json_type?
292
+ return self.parsed_response_body unless self.expected_type
293
+
294
+ if self.expected_type == Array
295
+ return self.fail_with("response body isn't a JSON Array") unless
296
+ self.parsed_response_body.is_a?(Array)
297
+ elsif self.expected_type == Object || self.expected_type == Hash
298
+ return self.fail_with("response body isn't a JSON Object") unless
299
+ self.parsed_response_body.is_a?(Hash)
300
+ else
301
+ warn "A valid JSON response can't be a %p!" % [self.expected_type]
302
+ end
303
+
304
+ return true
305
+ end
306
+
307
+ ### Return an Array of descriptions of the members that were expected to be included in the
308
+ ### response body, if any were specified. If none were specified, returns an empty
309
+ ### Array.
310
+ protected def describe_additional_expectations
311
+ return self.additional_expectations.map(&:description)
312
+ end
313
+
314
+ ### Check that any additional matchers registered via the `.and` mutator also
315
+ ### match the parsed response body.
316
+ protected def matches_additional_expectations?
317
+ r = self.additional_expectations.all? do |matcher|
318
+ matcher.matches?(self.parsed_response_body) ||
319
+ fail_with(matcher.failure_message)
320
+ end
321
+ return r
322
+ end
323
+ end
324
+
325
+ class HaveStatusMatcher
326
+ include RSpec::Matchers
327
+
328
+ def initialize(expected_status)
329
+ @expected_status = expected_status
330
+ end
331
+
332
+ def matches?(response)
333
+ @response = response
334
+ unless response.respond_to?(:status)
335
+ raise "response has no .status method, did you pass in last_response.status " \
336
+ "instead of last_response?"
337
+ end
338
+ return response.status == @expected_status
339
+ end
340
+
341
+ def failure_message
342
+ parsed = self.parsed_body
343
+ msg = "expected response status %d, got a %d response instead\n" % [@expected_status, @response.status]
344
+ if parsed&.include?("error")
345
+ suffix = +""
346
+ if (errmsg = parsed["error"].delete("message"))
347
+ suffix << ("\nMessage: %s" % [errmsg])
348
+ end
349
+ if (backtrace = parsed["error"].delete("backtrace"))
350
+ suffix << ("\nBacktrace:\n%s" % [backtrace])
351
+ end
352
+ msg << ("Body: %s%s" % [parsed.to_json, suffix])
353
+ else
354
+ msg << ("Body: %s" % [@response.body])
355
+ end
356
+ return msg
357
+ end
358
+
359
+ protected def parsed_body
360
+ return Oj.load(@response.body)
361
+ rescue StandardError
362
+ return nil
363
+ end
364
+ end
365
+
366
+ # Matcher that will have a failure message if the response does not have the expected status.
367
+ #
368
+ # expect( last_response ).to have_status( 200 )
369
+ #
370
+ module_function def have_status(expected_status)
371
+ return HaveStatusMatcher.new(expected_status)
372
+ end
373
+
374
+ # Matcher for matching a session cookie
375
+ #
376
+ # expect(last_response).to have_session_cookie
377
+ #
378
+ RSpec::Matchers.define(:have_session_cookie) do
379
+ look_for = Webhookdb::Service::SESSION_COOKIE + "="
380
+
381
+ match do |response|
382
+ response["Set-Cookie"]&.include?(look_for)
383
+ end
384
+
385
+ failure_message do |string|
386
+ "expected response Set-Cookie to include %p but got: %p" % [look_for, string]
387
+ end
388
+ end
389
+
390
+ ### Create a new matcher that will expect the response to have a JSON body of
391
+ ### the +expected_type+. If +expected_type+ is omitted, any JSON body will be sufficient
392
+ ### for a match.
393
+ module_function def have_json_body(expected_type=nil)
394
+ return HaveJSONBodyMatcher.new(expected_type)
395
+ end
396
+
397
+ ### Parse the body of the last response and return it as a Ruby object.
398
+ module_function def last_response_json_body(expected_type=nil)
399
+ matcher = have_json_body(expected_type)
400
+ expect(last_response).to(matcher)
401
+ return matcher.parsed_response_body
402
+ end
403
+
404
+ #
405
+ # Rack::Test overrides: Makes posts, puts, and patches JSON requests by default.
406
+ #
407
+
408
+ module WebhookdbTestMethods
409
+ include Rack::Test::Methods
410
+
411
+ def post(uri, params={}, env={}, &)
412
+ env, params = make_json_request(env, params)
413
+ super
414
+ end
415
+
416
+ def put(uri, params={}, env={}, &)
417
+ env, params = make_json_request(env, params)
418
+ super
419
+ end
420
+
421
+ def patch(uri, params={}, env={}, &)
422
+ env, params = make_json_request(env, params)
423
+ super
424
+ end
425
+
426
+ def make_json_request(env, params)
427
+ env["CONTENT_TYPE"] ||= "application/json"
428
+ params = Webhookdb::Json.encode(params) if env["CONTENT_TYPE"] == "application/json" && !params.is_a?(String)
429
+ return env, params
430
+ end
431
+ end
432
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples "a service column converter" do |isomorphic_proc|
4
+ let(:initial_value) { super() }
5
+ let(:resource) { nil }
6
+ let(:event) { nil }
7
+ let(:enrichment) { nil }
8
+ let(:service_integration) { nil }
9
+ let(:expected_value) { super() }
10
+ let(:db) { Webhookdb::Postgres::Model.db }
11
+
12
+ it "returns expected value using ruby proc" do
13
+ v = isomorphic_proc.ruby.call(initial_value, resource:, event:, enrichment:, service_integration:)
14
+ expect(v).to eq(expected_value)
15
+ end
16
+
17
+ it "handles nil as the value to its ruby proc without erroring" do
18
+ expect do
19
+ isomorphic_proc.ruby.call(nil, resource:, event:, enrichment:, service_integration:)
20
+ end.to_not raise_error
21
+ end
22
+
23
+ it "returns expected value using sql proc" do
24
+ e = isomorphic_proc.sql.call(initial_value)
25
+ v = db.select(e).first.to_a[0][1]
26
+ expect(v).to eq(expected_value)
27
+ end
28
+ end
29
+
30
+ RSpec.shared_examples "a service column defaulter" do |isomorphic_proc|
31
+ let(:resource) { nil }
32
+ let(:event) { nil }
33
+ let(:enrichment) { nil }
34
+ let(:service_integration) { nil }
35
+ let(:expected_value) { super() }
36
+ let(:expected) { eq(expected_value) }
37
+ let(:expected_query) { nil }
38
+ let(:db) { Webhookdb::Postgres::Model.db }
39
+
40
+ it "returns expected value using ruby proc" do
41
+ v = isomorphic_proc.ruby.call(resource:, event:, enrichment:, service_integration:)
42
+ expect(v).to expected
43
+ end
44
+
45
+ it "returns expected value using sql proc" do
46
+ e = isomorphic_proc.sql.call(service_integration:)
47
+ if expected_query.respond_to?(:match)
48
+ expect(db.select(e).sql).to match(expected_query)
49
+ elsif expected_query
50
+ expect(db.select(e).sql).to eq(expected_query)
51
+ else
52
+ v = db.select(e).first.to_a[0][1]
53
+ expect(v).to expected
54
+ end
55
+ end
56
+ end