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,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/postgres/model"
4
+
5
+ require "webhookdb/message"
6
+
7
+ class Webhookdb::Message::Delivery < Webhookdb::Postgres::Model(:message_deliveries)
8
+ plugin :timestamps
9
+ plugin :soft_deletes
10
+
11
+ many_to_one :recipient, class: "Webhookdb::Customer"
12
+ one_to_many :bodies, class: "Webhookdb::Message::Body"
13
+
14
+ dataset_module do
15
+ def unsent
16
+ return self.not_soft_deleted.where(sent_at: nil)
17
+ end
18
+
19
+ def sent
20
+ return self.not_soft_deleted.exclude(sent_at: nil)
21
+ end
22
+
23
+ def to_customers(customers)
24
+ emails = customers.is_a?(Sequel::Dataset) ? customers.select(:email) : customers.map(&:email)
25
+ return self.where(Sequel[to: emails] | Sequel[recipient: customers])
26
+ end
27
+ end
28
+
29
+ def initialize(*)
30
+ super
31
+ self[:extra_fields] ||= {}
32
+ end
33
+
34
+ def body_with_mediatype(mt)
35
+ return self.bodies.find { |b| b.mediatype == mt }
36
+ end
37
+
38
+ def body_with_mediatype!(mt)
39
+ (b = self.body_with_mediatype(mt)) or raise "Delivery #{self.id} has no body with mediatype #{mt}"
40
+ return b
41
+ end
42
+
43
+ def sent?
44
+ return self.sent_at ? true : false
45
+ end
46
+
47
+ def send!
48
+ return nil if self.sent? || self.soft_deleted?
49
+ self.db.transaction do
50
+ self.lock!
51
+ return nil if self.sent? || self.soft_deleted?
52
+ begin
53
+ transport_message_id = self.transport.send!(self)
54
+ rescue Webhookdb::Message::Transport::UndeliverableRecipient
55
+ self.logger.warn("undeliverable_recipient", recipient: self.to, message_delivery_id: self.id)
56
+ self.soft_delete
57
+ return self
58
+ end
59
+ if transport_message_id.blank?
60
+ self.logger.error("empty_transport_message_id", message_delivery_id: self.id)
61
+ transport_message_id = "WARNING-NOT-SET"
62
+ end
63
+ self.update(transport_message_id:, sent_at: Time.now)
64
+ return self
65
+ end
66
+ end
67
+
68
+ def transport
69
+ return Webhookdb::Message::Transport.for(self.transport_type)
70
+ end
71
+
72
+ def transport!
73
+ return Webhookdb::Message::Transport.for!(self.transport_type)
74
+ end
75
+
76
+ def self.preview(template_class_name, transport: :email, rack_env: Webhookdb::RACK_ENV, commit: false)
77
+ raise "Can only preview in development or commit:false" unless rack_env == "development" || !commit
78
+
79
+ Gem.find_files("webhookdb/messages/**/*.rb").each do |path|
80
+ require path
81
+ end
82
+
83
+ begin
84
+ template_class = "Webhookdb::Messages::#{template_class_name}".constantize
85
+ rescue NameError
86
+ raise Webhookdb::Message::MissingTemplateError, "Webhookdb::Messages::#{template_class_name} not found"
87
+ end
88
+
89
+ require "webhookdb/fixtures"
90
+ Webhookdb::Fixtures.load_all
91
+
92
+ delivery = nil
93
+ self.db.transaction(rollback: commit ? nil : :always) do
94
+ to = Webhookdb::Fixtures.customer.create
95
+ template = template_class.fixtured(to)
96
+ delivery = template.dispatch(to, transport:)
97
+ delivery.bodies # Fetch this ahead of time so it is there after rollback
98
+ end
99
+ return delivery
100
+ end
101
+ end
102
+
103
+ # Table: message_deliveries
104
+ # ---------------------------------------------------------------------------------------------------------------------
105
+ # Columns:
106
+ # id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
107
+ # created_at | timestamp with time zone | NOT NULL DEFAULT now()
108
+ # updated_at | timestamp with time zone |
109
+ # template | text | NOT NULL
110
+ # transport_type | text | NOT NULL
111
+ # transport_service | text | NOT NULL
112
+ # transport_message_id | text |
113
+ # sent_at | timestamp with time zone |
114
+ # to | text | NOT NULL
115
+ # recipient_id | integer |
116
+ # extra_fields | jsonb | NOT NULL DEFAULT '{}'::jsonb
117
+ # soft_deleted_at | timestamp with time zone |
118
+ # Indexes:
119
+ # message_deliveries_pkey | PRIMARY KEY btree (id)
120
+ # message_deliveries_transport_message_id_key | UNIQUE btree (transport_message_id)
121
+ # message_deliveries_recipient_id_index | btree (recipient_id)
122
+ # message_deliveries_sent_at_index | btree (sent_at)
123
+ # Foreign key constraints:
124
+ # message_deliveries_recipient_id_fkey | (recipient_id) REFERENCES customers(id) ON DELETE SET NULL
125
+ # Referenced By:
126
+ # message_bodies | message_bodies_delivery_id_fkey | (delivery_id) REFERENCES message_deliveries(id) ON DELETE CASCADE
127
+ # ---------------------------------------------------------------------------------------------------------------------
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "appydays/configurable"
4
+ require "mail"
5
+ require "premailer"
6
+
7
+ require "webhookdb/message/transport"
8
+
9
+ class Webhookdb::Message::EmailTransport < Webhookdb::Message::Transport
10
+ include Appydays::Configurable
11
+
12
+ register_transport(:email)
13
+
14
+ configurable(:email) do
15
+ setting :allowlist, ["*@lithic.tech", "*@webhookdb.com"], convert: ->(s) { s.split }
16
+ setting :from, "WebhookDB <hello@webhookdb.com>"
17
+
18
+ setting :smtp_host, "localhost"
19
+ setting :smtp_port, 18_012
20
+ setting :smtp_user, ""
21
+ setting :smtp_password, ""
22
+ setting :smtp_starttls, false
23
+
24
+ # If this is a recognized value, certain special behavior is used,
25
+ # particularly around message ids and metadata.
26
+ # Currently supported values:
27
+ #
28
+ # - postmark: Set the X-PM-Metadata-messageid field and some other fields.
29
+ #
30
+ # If you need other behavior, you can open an issue or pull request.
31
+ # Unsupported values are ignored.
32
+ setting :smtp_provider, ""
33
+ # Additional headers sent in each email.
34
+ setting :smtp_headers, {}, convert: ->(s) { JSON.parse(s) }
35
+
36
+ # Only really used during testing and development.
37
+ # We don't expect this to be running in production.
38
+ setting :mailpit_url, "http://localhost:18011"
39
+ end
40
+
41
+ def type
42
+ return :email
43
+ end
44
+
45
+ def service
46
+ return "smtp"
47
+ end
48
+
49
+ def supports_layout?
50
+ return true
51
+ end
52
+
53
+ def add_bodies(delivery, content)
54
+ pm = Premailer.new(
55
+ content.to_s,
56
+ with_html_string: true,
57
+ warn_level: Premailer::Warnings::SAFE,
58
+ )
59
+
60
+ begin
61
+ subject = content[:subject]
62
+ rescue TypeError, NoMethodError
63
+ subject = nil
64
+ end
65
+
66
+ raise "content %p is missing a subject" % content unless subject
67
+
68
+ bodies = []
69
+ bodies << delivery.add_body(content: content[:subject], mediatype: "subject")
70
+ bodies << delivery.add_body(content: pm.to_plain_text, mediatype: "text/plain")
71
+ bodies << delivery.add_body(content: pm.to_inline_css, mediatype: "text/html")
72
+ return bodies
73
+ end
74
+
75
+ def allowlisted?(address)
76
+ return self.class.allowlist.any? { |pattern| File.fnmatch(pattern, address) }
77
+ end
78
+
79
+ def send!(delivery)
80
+ unless allowlisted?(delivery.to)
81
+ raise Webhookdb::Message::Transport::UndeliverableRecipient,
82
+ "#{delivery.to} is not allowlisted"
83
+ end
84
+
85
+ from = delivery.extra_fields["from"].present? ? delivery.extra_fields["from"] : self.class.from
86
+ to = self.format_email_name(delivery.to, delivery.recipient&.name)
87
+ message_id = SecureRandom.uuid.to_s
88
+ this = self
89
+ Mail.deliver do
90
+ delivery_method(
91
+ :smtp,
92
+ address: this.class.smtp_host,
93
+ port: this.class.smtp_port,
94
+ user_name: this.class.smtp_user,
95
+ password: this.class.smtp_password,
96
+ enable_starttls_auto: this.class.smtp_starttls,
97
+ )
98
+ this.class.smtp_headers.each do |k, v|
99
+ header[k] = v
100
+ end
101
+ custom_method = :"_handle_#{this.class.smtp_provider}"
102
+ this.send(custom_method, delivery, self, message_id) if this.respond_to?(custom_method)
103
+ from from
104
+ to to
105
+ reply_to(delivery.extra_fields["reply_to"]) if delivery.extra_fields["reply_to"].present?
106
+ subject delivery.body_with_mediatype("subject")&.content
107
+ text_part do
108
+ content_type "text/plain; charset=UTF-8"
109
+ body delivery.body_with_mediatype!("text/plain")&.content
110
+ end
111
+ html_part do
112
+ content_type "text/html; charset=UTF-8"
113
+ body delivery.body_with_mediatype!("text/html")&.content
114
+ end
115
+ end
116
+ return message_id
117
+ end
118
+
119
+ protected def extract_email_part(email)
120
+ split = /(?:(?<address>.+)\s)?<?(?<email>.+@[^>]+)>?/.match(email)
121
+ return split[:email]
122
+ end
123
+
124
+ def format_email_name(email, name)
125
+ return email if name.blank?
126
+ return "#{name} <#{email}>"
127
+ end
128
+
129
+ def _handle_postmark(delivery, mail, message_id)
130
+ mail.header["X-PM-Metadata-messageid"] = message_id
131
+ mail.header["X-PM-Tag"] = delivery.template
132
+ end
133
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/message/transport"
4
+
5
+ class Webhookdb::Message::FakeTransport < Webhookdb::Message::Transport
6
+ extend Webhookdb::MethodUtilities
7
+
8
+ register_transport(:fake)
9
+
10
+ singleton_attr_reader :sent_deliveries
11
+ @sent_deliveries = []
12
+
13
+ singleton_attr_accessor :disable_func
14
+ @disable_func = nil
15
+
16
+ singleton_attr_accessor :return_nil_on_send
17
+ @return_nil_on_send = false
18
+
19
+ def self.reset!
20
+ self.sent_deliveries.clear
21
+ self.disable_func = nil
22
+ self.return_nil_on_send = false
23
+ end
24
+
25
+ def type
26
+ return :fake
27
+ end
28
+
29
+ def service
30
+ return "fake"
31
+ end
32
+
33
+ def supports_layout?
34
+ return true
35
+ end
36
+
37
+ def add_bodies(delivery, content)
38
+ bodies = []
39
+ bodies << delivery.add_body(content: content.to_s, mediatype: "text/plain")
40
+ return bodies
41
+ end
42
+
43
+ def send!(delivery)
44
+ if Webhookdb::Message::FakeTransport.disable_func&.call(delivery)
45
+ raise Webhookdb::Message::Transport::UndeliverableRecipient,
46
+ "Did not deliver Delivery[#{delivery.id}] to #{delivery.to} because it was skipped by disable_func"
47
+ end
48
+
49
+ Webhookdb.logger.debug "Storing Delivery[%d] to %s as sent" % [delivery.id, delivery.to]
50
+ Webhookdb::Message::FakeTransport.sent_deliveries << delivery
51
+ return nil if Webhookdb::Message::FakeTransport.return_nil_on_send
52
+ return "#{delivery.id}-#{SecureRandom.hex(6)}"
53
+ end
54
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Webhookdb::Message
4
+ class CustomerDrop < Liquid::Drop
5
+ def initialize(recipient)
6
+ @recipient = recipient
7
+ super()
8
+ end
9
+
10
+ def to
11
+ return @recipient.to
12
+ end
13
+
14
+ def name
15
+ return @recipient.customer&.name
16
+ end
17
+
18
+ def greeting
19
+ return nil unless @recipient.customer
20
+ return @recipient.customer.greeting
21
+ end
22
+ end
23
+
24
+ class EnvironmentDrop < Liquid::Drop
25
+ def name
26
+ return Webhookdb::RACK_ENV
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/message"
4
+
5
+ # Template is the base class for all message templates.
6
+ # Every message (email, and/or SMS, etc) has a Template
7
+ # that defines how to look up its text template and the dynamic data
8
+ # for rendering into the template.
9
+ # Subclasses should override methods to control the rendering behavior;
10
+ # see the method docs to see what is expected to be overridden.
11
+ class Webhookdb::Message::Template
12
+ # Override to return a new version of the template,
13
+ # with its data fixtured. It is used for message previewing.
14
+ # The argument is the message recipient,
15
+ # because they may need to be used to build resources off of.
16
+ #
17
+ # Only needs to be overridden if the template constructor takes arguments.
18
+ # Assume that fixtures are loaded when this method is called;
19
+ # do not require them as part of your code.
20
+ def self.fixtured(_recipient)
21
+ return self.new
22
+ end
23
+
24
+ def dispatch(to, transport: Webhookdb::Message::DEFAULT_TRANSPORT)
25
+ return Webhookdb::Message.dispatch(self, to, transport)
26
+ end
27
+
28
+ def dispatch_email(to)
29
+ return self.dispatch(to, transport: :email)
30
+ end
31
+
32
+ # The folder containing this template. Templates in the root template directory should use nil.
33
+ def template_folder
34
+ return nil
35
+ end
36
+
37
+ # The name of the template. By default, it is tied to the name of the class,
38
+ # so Messages::NewCustomer looks for 'new_customer' templates.
39
+ # However, a subclass can override this to not tie the template to the class name.
40
+ def template_name
41
+ return self.class.name.demodulize.underscore
42
+ end
43
+
44
+ def full_template_name
45
+ fld = self.template_folder.present? ? "#{self.template_folder}/" : ""
46
+ return "#{fld}#{self.template_name}"
47
+ end
48
+
49
+ def template_path(transport)
50
+ return Webhookdb::Message::DATA_DIR + "templates/#{self.full_template_name}.#{transport}.liquid"
51
+ end
52
+
53
+ # The layout for the template. See the 'layouts' folder in the message data directory.
54
+ def layout
55
+ return "standard"
56
+ end
57
+
58
+ def layout_path(transport)
59
+ return nil if self.layout.nil?
60
+ return Webhookdb::Message::DATA_DIR + "layouts/#{self.layout}.#{transport}.liquid"
61
+ end
62
+
63
+ # The hash that is used for the rendering of the template.
64
+ # These must be simple types (strings, ints, bools, etc), or Liquid::Drop subclasses.
65
+ # By default, templates are rendered with some default variables,
66
+ # such as 'recipient', 'environment', and 'app_url'.
67
+ def liquid_drops
68
+ return {
69
+ api_url: Webhookdb.api_url,
70
+ support_email: Webhookdb.support_email,
71
+ oss_repo: Webhookdb.oss_repo_url,
72
+ docs_url: "https://docs.webhookdb.com",
73
+ }
74
+ end
75
+
76
+ # Liquify wraps any object in a Liquification.
77
+ def liquify(o)
78
+ return Webhookdb::Liquid::Liquification.new(o)
79
+ end
80
+
81
+ # Return a hash of special fields for that this delivery should use.
82
+ # Necessary for deliveries that need to carry along some metadata. For example:
83
+ # {'reply_to' => 'customer@gmail.com'}
84
+ # for customers who send support requests.
85
+ # These fields are subject to flux and change and may only be applicable to some transports.
86
+ def extra_fields
87
+ return {}
88
+ end
89
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/message"
4
+
5
+ class Webhookdb::Message::Transport
6
+ extend Webhookdb::MethodUtilities
7
+
8
+ class Error < StandardError; end
9
+ class UndeliverableRecipient < Error; end
10
+
11
+ singleton_attr_reader :transports
12
+ @transports = {}
13
+
14
+ singleton_attr_accessor :override
15
+
16
+ def self.register_transport(type)
17
+ Webhookdb::Message::Transport.transports[type] = self.new
18
+ end
19
+
20
+ def self.for(type)
21
+ type = Webhookdb::Message::Transport.override || type
22
+ return Webhookdb::Message::Transport.transports[type.to_sym]
23
+ end
24
+
25
+ def self.for!(type)
26
+ (t = self.for(type)) or raise Webhookdb::Message::InvalidTransportError, "invalid transport: %p" % type
27
+ return t
28
+ end
29
+
30
+ # Override this if a transport needs a different 'to' than the email,
31
+ # like for text messages.
32
+ def recipient(to)
33
+ if to.is_a?(Webhookdb::Customer)
34
+ (email = to.email) or raise "Customer #{to.id} has no default email"
35
+ return Webhookdb::Message::Recipient.new(email, to)
36
+ end
37
+ return Webhookdb::Message::Recipient.new(to, nil)
38
+ end
39
+
40
+ def send!(_delivery)
41
+ raise "Must implement in subclass. Call 3rd party with message/content and return transport ID."
42
+ end
43
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "appydays/configurable"
4
+ require "liquid"
5
+
6
+ module Webhookdb::Messages
7
+ end
8
+
9
+ module Webhookdb::Liquid
10
+ end
11
+
12
+ module Webhookdb::Message
13
+ include Appydays::Configurable
14
+ extend Webhookdb::MethodUtilities
15
+
16
+ require "webhookdb/liquid/expose"
17
+ require "webhookdb/liquid/filters"
18
+ require "webhookdb/liquid/liquification"
19
+ require "webhookdb/liquid/partial"
20
+
21
+ require "webhookdb/message/email_transport"
22
+ require "webhookdb/message/fake_transport"
23
+ require "webhookdb/message/transport"
24
+ require "webhookdb/message/liquid_drops"
25
+ require "webhookdb/message/template"
26
+
27
+ DEFAULT_TRANSPORT = :email
28
+ DATA_DIR = Webhookdb::DATA_DIR + "messages"
29
+
30
+ configurable(:messages) do
31
+ after_configured do
32
+ Liquid::Template.error_mode = :strict
33
+ Liquid::Template.file_system = Liquid::LocalFileSystem.new(DATA_DIR, "%s.liquid")
34
+ end
35
+ end
36
+
37
+ # Create a Webhookdb::Message::Delivery ready to deliver (rendered, all bodies set up)
38
+ # using the given transport_type to the given user.
39
+ def self.dispatch(template, to, transport_type)
40
+ (transport = Webhookdb::Message::Transport.for(transport_type)) or
41
+ raise InvalidTransportError, "Invalid transport #{transport_type}"
42
+ recipient = transport.recipient(to)
43
+
44
+ contents = self.render(template, transport_type, recipient)
45
+
46
+ Webhookdb::Message::Delivery.db.transaction do
47
+ delivery = Webhookdb::Message::Delivery.create(
48
+ template: template.full_template_name,
49
+ transport_type: transport.type,
50
+ transport_service: transport.service,
51
+ to: recipient.to,
52
+ recipient: recipient.customer,
53
+ extra_fields: template.extra_fields,
54
+ )
55
+ transport.add_bodies(delivery, contents)
56
+ delivery.publish_deferred("dispatched", delivery.id)
57
+ return delivery
58
+ end
59
+ end
60
+
61
+ # Render the transport-specific version of the given template
62
+ # and return a the rendering (content and exposed variables).
63
+ #
64
+ # Templates can expose data to the caller by using the 'expose' tag,
65
+ # like {% expose subject %}Hello from Webhookdb!{% endexpose %}.
66
+ # This is available as [:subject] on the returned rendering.
67
+ def self.render(template, transport_type, recipient)
68
+ template_file = template.template_path(transport_type)
69
+ raise MissingTemplateError, "#{template_file} does not exist" unless template_file.exist?
70
+
71
+ drops = template.liquid_drops.stringify_keys.merge(
72
+ "recipient" => Webhookdb::Message::CustomerDrop.new(recipient),
73
+ "environment" => Webhookdb::Message::EnvironmentDrop.new,
74
+ "app_url" => Webhookdb.app_url,
75
+ )
76
+
77
+ content_tmpl = Liquid::Template.parse(template_file.read)
78
+ # The 'expose' drop smashes data into the register.
79
+ # We need to keep track of the register to get the subject back out,
80
+ # so we need to make our own context.
81
+ lctx = Liquid::Context.new(
82
+ [drops, content_tmpl.assigns],
83
+ content_tmpl.instance_assigns,
84
+ content_tmpl.registers,
85
+ true,
86
+ content_tmpl.resource_limits,
87
+ )
88
+ content = content_tmpl.render!(lctx, strict_variables: true)
89
+
90
+ transport = Webhookdb::Message::Transport.for(transport_type)
91
+ if transport.supports_layout?
92
+ layout_file = template.layout_path(transport_type)
93
+ if layout_file
94
+ raise MissingTemplateError, "#{template_file} does not exist" unless layout_file.exist?
95
+ layout_tmpl = Liquid::Template.parse(layout_file.read)
96
+ drops["content"] = content.dup
97
+ content = layout_tmpl.render!(drops, strict_variables: true, registers: content_tmpl.registers)
98
+ end
99
+ end
100
+
101
+ return Rendering.new(content, lctx.registers)
102
+ end
103
+
104
+ def self.send_unsent
105
+ Webhookdb::Message::Delivery.unsent.each(&:send!)
106
+ end
107
+
108
+ class InvalidTransportError < StandardError; end
109
+
110
+ class MissingTemplateError < StandardError; end
111
+
112
+ # Presents a homogeneous interface for a given 'to' value (email vs. customer, for example).
113
+ # .to will always be a plain object, and .customer will be a +Webhookdb::Customer+ if present.
114
+ class Recipient
115
+ attr_reader :to, :customer
116
+
117
+ def initialize(to, customer)
118
+ @to = to
119
+ @customer = customer
120
+ end
121
+ end
122
+
123
+ # String-like type representing the output of a rendering operation.
124
+ # Use [key] to access exposed variables, as per +LiquidExpose+.
125
+ class Rendering
126
+ attr_reader :contents, :exposed
127
+
128
+ def initialize(contents, exposed={})
129
+ @contents = contents
130
+ @exposed = exposed
131
+ end
132
+
133
+ def [](key)
134
+ return self.exposed[key]
135
+ end
136
+
137
+ def to_s
138
+ return self.contents
139
+ end
140
+
141
+ def respond_to_missing?(name, *args)
142
+ return true if super
143
+ return self.contents.respond_to?(name)
144
+ end
145
+
146
+ def method_missing(name, *, &)
147
+ return self.contents.respond_to?(name) ? self.contents.send(name, *, &) : super
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/message/template"
4
+
5
+ class Webhookdb::Messages::ErrorIcalendarFetch < Webhookdb::Message::Template
6
+ def self.fixtured(_recipient)
7
+ sint = Webhookdb::Fixtures.service_integration.create
8
+ return self.new(sint, "calendar123",
9
+ response_status: 403, request_url: "/foo", request_method: "GET", response_body: "hi",)
10
+ end
11
+
12
+ def initialize(service_integration, external_calendar_id, request_url:, request_method:, response_status:,
13
+ response_body:)
14
+ @service_integration = service_integration
15
+ @external_calendar_id = external_calendar_id
16
+ @request_url = request_url
17
+ @request_method = request_method
18
+ @response_status = response_status
19
+ @response_body = response_body
20
+ super()
21
+ end
22
+
23
+ def signature
24
+ ehash = Digest::MD5.hexdigest(@kw.to_s)
25
+ return "msg-#{self.full_template_name}-sint:#{@service_integration.id}-eid:#{@external_calendar_id}-err:#{ehash}"
26
+ end
27
+
28
+ def template_folder = "errors"
29
+ def template_name = "icalendar_fetch"
30
+
31
+ def liquid_drops
32
+ return super.merge(
33
+ service_name: @service_integration.service_name,
34
+ opaque_id: @service_integration.opaque_id,
35
+ request_method: @request_method,
36
+ request_url: @request_url,
37
+ response_status: @response_status,
38
+ response_body: @response_body,
39
+ external_calendar_id: @external_calendar_id,
40
+ )
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webhookdb/message/template"
4
+
5
+ class Webhookdb::Messages::Invite < Webhookdb::Message::Template
6
+ def self.fixtured(recipient)
7
+ org = Webhookdb::Fixtures.organization.with_member(recipient).create
8
+ membership = org.all_memberships[0]
9
+ return self.new(membership)
10
+ end
11
+
12
+ def initialize(membership)
13
+ @membership = membership
14
+ super()
15
+ end
16
+
17
+ def liquid_drops
18
+ return super.merge(
19
+ organization_name: @membership.organization_name,
20
+ invite_code: @membership.invitation_code,
21
+ )
22
+ end
23
+ end