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,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "appydays/configurable"
4
+ require "appydays/loggable"
5
+
6
+ require "webhookdb"
7
+
8
+ # Keep a dynamic cache of open database connections.
9
+ # Very similar in behavior to Sequel::DATABASES,
10
+ # but we need to prune connections that have not been inactive for a while.
11
+ #
12
+ # When `borrow` is called, either a new connection is made,
13
+ # or an existing one used, for that URL. The connection is yield to the block.
14
+ #
15
+ # Then, after the block is called,
16
+ # if 'prune_interval' has elapsed since the last prune,
17
+ # prune all connections with 0 current connections,
18
+ # _other than the connection just used_.
19
+ # Because this connection was just used,
20
+ # we assume it will be used again soon.
21
+ #
22
+ # The idea here is that:
23
+ # - We cannot connect to the DB statically; each org can have its own DB,
24
+ # so storing it statically would increase DB connections to the the number of orgs in the database.
25
+ # - So we replace the organization/synchronization done in Sequel::DATABASES with ConnectionCache.
26
+ # - Any number of worker threads need access to the same DB; rather than connecting inline,
27
+ # which is very slow, all DB connections for an org (or across orgs if not in database isolation)
28
+ # can share connections via ConnectionCache.
29
+ # - In single-org/db environments, the active organization will always always be the same,
30
+ # so the connection is never returned.
31
+ # - In multi-org/db environments, busy orgs will likely stay busy. But a reconnect isn't the end
32
+ # of the world.
33
+ # - It seems more efficient to be pessimistic about future use, and prune anything with 0 connections,
34
+ # rather than optimistic, and use an LRU or something similar, since the connections are somewhat
35
+ # expensive resources to keep open for now reason. That said, we could switch this out for an LRU
36
+ # it the pessimistic pruning results in many reconnections. It would also be reasonable to increase
37
+ # the prune interval to avoid disconnecting as frequently.
38
+ #
39
+ # Note that, due to certain implementation details, such as setting timeouts and automatic transaction handling,
40
+ # we implement our own threaded connection pooling, so use the SingleThreadedConnectionPool in Sequel
41
+ # and manage multiple threads on our own.
42
+ class Webhookdb::ConnectionCache
43
+ include Appydays::Configurable
44
+ include Appydays::Loggable
45
+ extend Webhookdb::MethodUtilities
46
+ include Webhookdb::Dbutil
47
+
48
+ class ReentranceError < StandardError; end
49
+
50
+ configurable(:connection_cache) do
51
+ # If this many seconds has elapsed since the last connecton was borrowed,
52
+ # prune connections with no pending borrows.
53
+ setting :prune_interval, 120
54
+
55
+ # Seconds for the :fast timeout option.
56
+ setting :timeout_fast, 30
57
+ # Seconds for the :slow timeout option.
58
+ setting :timeout_slow, 180
59
+ # Seconds for the :slow_schema timeout option.
60
+ setting :timeout_slow_schema, 30.minutes.to_i
61
+ end
62
+
63
+ singleton_attr_accessor :_instance
64
+
65
+ def self.borrow(url, **kw, &)
66
+ return self._instance.borrow(url, **kw, &)
67
+ end
68
+
69
+ def self.disconnect(url)
70
+ self._instance.disconnect(url)
71
+ end
72
+
73
+ def self.force_disconnect_all
74
+ self._instance.force_disconnect_all
75
+ end
76
+
77
+ attr_accessor :dbs_for_urls, :prune_interval, :last_pruned_at
78
+
79
+ def initialize(prune_interval:)
80
+ @mutex = Mutex.new
81
+ @dbs_for_urls = {}
82
+ @prune_interval = prune_interval
83
+ @last_pruned_at = Time.now
84
+ end
85
+
86
+ # Connect to the database at the given URL.
87
+ # borrow is not re-entrant, so if the current thread already owns a connection
88
+ # to the given url, raise a ReentrantError.
89
+ # If the url has a DB not in use by any thread,
90
+ # yield that.
91
+ # If the url has no DBs opened, or all are checked out,
92
+ # create and yield a new connection.
93
+ # See class docs for more details.
94
+ def borrow(url, transaction: false, timeout: nil, &block)
95
+ raise LocalJumpError if block.nil?
96
+ raise ArgumentError, "url cannot be blank" if url.blank?
97
+ now = Time.now
98
+ if timeout.is_a?(Symbol)
99
+ timeout_name = "timeout_#{timeout}"
100
+ begin
101
+ timeout = Webhookdb::ConnectionCache.send(timeout_name)
102
+ rescue NoMethodError
103
+ raise NoMethodError, "no timeout accessor :#{timeout_name}"
104
+ end
105
+ end
106
+ t = Thread.current
107
+ conn = nil
108
+ @mutex.synchronize do
109
+ db_loans = @dbs_for_urls[url] ||= {loaned: {}, available: []}
110
+ if db_loans[:loaned].key?(t)
111
+ raise ReentranceError,
112
+ "ConnectionCache#borrow is not re-entrant for the same database since the connection has stateful config"
113
+ end
114
+ conn = db_loans[:available].pop || take_conn(url, single_threaded: true, extensions: [:pg_json, :pg_streaming])
115
+ db_loans[:loaned][t] = conn
116
+ end
117
+ conn << "SET statement_timeout TO #{timeout * 1000}" if timeout.present?
118
+ conn << "BEGIN;" if transaction
119
+ begin
120
+ result = yield conn
121
+ conn << "COMMIT;" if transaction
122
+ rescue Sequel::DatabaseError
123
+ conn << "ROLLBACK;" if transaction
124
+ raise
125
+ ensure
126
+ conn << "SET statement_timeout TO 0" if timeout.present?
127
+ @mutex.synchronize do
128
+ @dbs_for_urls[url][:loaned].delete(t)
129
+ @dbs_for_urls[url][:available] << conn
130
+ end
131
+ end
132
+ self.prune(url) if now > self.next_prune_at
133
+ return result
134
+ end
135
+
136
+ def next_prune_at = self.last_pruned_at + self.prune_interval
137
+
138
+ # Disconnect the cached connection for the given url,
139
+ # if any. In general, this is only needed when tearing down a database.
140
+ def disconnect(url)
141
+ raise ArgumentError, "url cannot be blank" if url.blank?
142
+ db_loans = @dbs_for_urls[url]
143
+ return if db_loans.nil?
144
+ if db_loans[:loaned].size.positive?
145
+ raise Webhookdb::InvalidPrecondition,
146
+ "url #{displaysafe_url(url)} still has #{db_loans[:loaned].size} active connections"
147
+ end
148
+ db_loans[:available].each(&:disconnect)
149
+ @dbs_for_urls.delete(url)
150
+ end
151
+
152
+ protected def prune(skip_url)
153
+ @dbs_for_urls.each do |url, db_loans|
154
+ next false if url == skip_url
155
+ db_loans[:available].each(&:disconnect)
156
+ end
157
+ self.last_pruned_at = Time.now
158
+ end
159
+
160
+ def force_disconnect_all
161
+ @dbs_for_urls.each_value do |db_loans|
162
+ db_loans[:available].each(&:disconnect)
163
+ db_loans[:loaned].each_value(&:disconnect)
164
+ end
165
+ @dbs_for_urls.clear
166
+ end
167
+
168
+ def summarize
169
+ return self.dbs_for_urls.transform_values do |loans|
170
+ {loaned: loans[:loaned].size, available: loans[:available].size}
171
+ end
172
+ end
173
+ end
174
+
175
+ Webhookdb::ConnectionCache._instance = Webhookdb::ConnectionCache.new(
176
+ prune_interval: Webhookdb::ConnectionCache.prune_interval,
177
+ )
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb"
4
+
5
+ module Webhookdb::Console
6
+ extend Webhookdb::MethodUtilities
7
+
8
+ class Error < StandardError; end
9
+
10
+ class UnsafeOperation < Error; end
11
+
12
+ class ForbiddenOperation < Error; end
13
+
14
+ singleton_attr_accessor :unsafe_mode
15
+ @unsafe_mode = false
16
+
17
+ singleton_attr_accessor :original_execute
18
+ @original_execute = nil
19
+
20
+ def self.enable_safe_mode
21
+ Webhookdb::Console.original_execute = Webhookdb::Postgres::Model.db.method(:execute)
22
+ Webhookdb::Postgres::Model.db.define_singleton_method(:execute) do |*args, &block|
23
+ sql = args.first
24
+
25
+ includes_where = sql.include?(" WHERE ")
26
+ is_update = sql.start_with?("UPDATE ")
27
+ is_delete = sql.start_with?("DELETE FROM")
28
+
29
+ raise ForbiddenOperation, "TRUNCATE is forbidden" if sql.start_with?("TRUNCATE TABLE")
30
+
31
+ raise ForbiddenOperation, "UPDATE without a WHERE is forbidden" if
32
+ is_update && !includes_where
33
+
34
+ raise ForbiddenOperation, "DELETE without a WHERE is forbidden" if
35
+ is_delete && !includes_where
36
+
37
+ raise UnsafeOperation, "DELETE is permitted only in an UNSAFE block" if
38
+ is_delete && includes_where && !Webhookdb::Console.unsafe_mode
39
+
40
+ Webhookdb::Console.original_execute.call(*args, &block)
41
+ end
42
+ end
43
+
44
+ def self.disable_safe_mode
45
+ Webhookdb::Postgres::Model.db.define_singleton_method(:execute, &Webhookdb::Console.original_execute)
46
+ end
47
+
48
+ def self.unsafe(&block)
49
+ raise LocalJumpError, "unsafe must be called with a block (do ... end)" unless block
50
+ self.unsafe_mode = true
51
+ begin
52
+ Webhookdb::Postgres::Model.db.transaction(&block)
53
+ ensure
54
+ self.unsafe_mode = false
55
+ end
56
+ end
57
+
58
+ def self.console_logger(ev)
59
+ Webhookdb.logger.info "ConsoleLogger: [%s] %s %p" % [ev.id, ev.name, ev.payload]
60
+ end
61
+
62
+ module MainMethods
63
+ def unsafe(&)
64
+ return Webhookdb::Console.unsafe(&)
65
+ end
66
+
67
+ def disconnect_db
68
+ Webhookdb::Customer.db.disconnect
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Webhookdb::Convertkit
4
+ include Appydays::Configurable
5
+
6
+ configurable(:convertkit) do
7
+ setting :http_timeout, 30
8
+ end
9
+
10
+ FIND_API_SECRET_HELP = %(- Go to https://app.convertkit.com/account_settings/advanced_settings,
11
+ - or from your ConvertKit Dashboard, go to your Advanced Account settings.
12
+ - Under the API Header you will see your API Secret, just under your API Key.
13
+ - Copy the API Secret.)
14
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Webhookdb::Crypto
4
+ def self.bin2hex(s)
5
+ return s.unpack1("H*")
6
+ end
7
+
8
+ def self.cipher
9
+ return OpenSSL::Cipher.new("aes-256-cbc")
10
+ end
11
+
12
+ # @return [Boxed]
13
+ def self.encryption_key
14
+ k = self.cipher.encrypt.random_key
15
+ return Boxed.from_raw(k)
16
+ end
17
+
18
+ # @param key [Boxed]
19
+ # @param value [Boxed]
20
+ # @return [Boxed]
21
+ def self.encrypt_value(key, value)
22
+ cipher = self.cipher.encrypt
23
+ cipher.key = key.raw
24
+ enc = cipher.update(value.raw) + cipher.final
25
+ return Boxed.from_raw(enc)
26
+ end
27
+
28
+ # @param key [Boxed]
29
+ # @param value [Boxed]
30
+ # @return [Boxed]
31
+ def self.decrypt_value(key, value)
32
+ cipher = self.cipher.decrypt
33
+ cipher.key = key.raw
34
+ dec = cipher.update(value.raw) + cipher.final
35
+ return Boxed.from_raw(dec)
36
+ end
37
+
38
+ class Boxed
39
+ def self.from_raw(bytestr)
40
+ raise ArgumentError, "bytes string cannot be nil" if bytestr.nil?
41
+ return self.new(bytestr, nil)
42
+ end
43
+
44
+ def self.from_b64(b64str)
45
+ raise ArgumentError, "base64 string cannot be nil" if b64str.nil?
46
+ return self.new(nil, b64str)
47
+ end
48
+
49
+ def initialize(raw, b64)
50
+ @raw = raw
51
+ @b64 = b64
52
+ end
53
+
54
+ # @return [String]
55
+ def base64
56
+ @b64 ||= Base64.urlsafe_encode64(@raw)
57
+ return @b64
58
+ end
59
+
60
+ # @return [String]
61
+ def raw
62
+ @raw ||= Base64.urlsafe_decode64(@b64)
63
+ return @raw
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ require "webhookdb/postgres"
6
+ require "webhookdb/customer"
7
+
8
+ class Webhookdb::Customer::ResetCode < Webhookdb::Postgres::Model(:customer_reset_codes)
9
+ class Unusable < StandardError; end
10
+
11
+ TOKEN_LENGTH = 6
12
+
13
+ plugin :timestamps
14
+
15
+ many_to_one :customer, class: Webhookdb::Customer
16
+
17
+ dataset_module do
18
+ def usable
19
+ return self.where(Sequel[used: false] & Sequel.expr { expire_at > Sequel.function(:now) })
20
+ end
21
+ end
22
+
23
+ # Invoke the given block with the reset code referred to by token.
24
+ # Raise Unusable if code is unusable.
25
+ def self.use_code_with_token(token)
26
+ raise LocalJumpError unless block_given?
27
+
28
+ code = self.usable[token:]
29
+ raise Unusable unless code&.usable?
30
+
31
+ code.db.transaction do
32
+ code.use!
33
+ yield(code)
34
+ end
35
+ end
36
+
37
+ def initialize(*)
38
+ super
39
+ self.token ||= Array.new(TOKEN_LENGTH) { rand(0..9) }.join
40
+ self.expire_at ||= 15.minutes.from_now
41
+ end
42
+
43
+ def expire!
44
+ self.update(expire_at: Time.now)
45
+ return self
46
+ end
47
+
48
+ def expired?
49
+ return self.expire_at < Time.now
50
+ end
51
+
52
+ def use!
53
+ now = Time.now
54
+ self.customer.reset_codes_dataset.usable.update(expire_at: now)
55
+ self.update(used: true, expire_at: now)
56
+ return self
57
+ end
58
+
59
+ def used?
60
+ return self.used
61
+ end
62
+
63
+ def usable?
64
+ return false if self.used?
65
+ return !self.expired?
66
+ end
67
+
68
+ #
69
+ # :section: Sequel Validation
70
+ #
71
+
72
+ def validate
73
+ super
74
+ self.validates_includes(["email"], :transport)
75
+ end
76
+ end
77
+
78
+ # Table: customer_reset_codes
79
+ # -------------------------------------------------------------------------------------------------
80
+ # Columns:
81
+ # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
82
+ # created_at | timestamp with time zone | NOT NULL DEFAULT now()
83
+ # updated_at | timestamp with time zone |
84
+ # transport | text | NOT NULL
85
+ # token | text | NOT NULL
86
+ # used | boolean | NOT NULL DEFAULT false
87
+ # expire_at | timestamp with time zone | NOT NULL
88
+ # customer_id | integer | NOT NULL
89
+ # Indexes:
90
+ # customer_reset_codes_pkey | PRIMARY KEY btree (id)
91
+ # customer_reset_codes_customer_id_index | btree (customer_id)
92
+ # Foreign key constraints:
93
+ # customer_reset_codes_customer_id_fkey | (customer_id) REFERENCES customers(id) ON DELETE CASCADE
94
+ # -------------------------------------------------------------------------------------------------