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.
- checksums.yaml +7 -0
- data/data/messages/layouts/blank.email.liquid +10 -0
- data/data/messages/layouts/minimal.email.liquid +28 -0
- data/data/messages/layouts/standard.email.liquid +28 -0
- data/data/messages/partials/button.liquid +15 -0
- data/data/messages/partials/environment_banner.liquid +9 -0
- data/data/messages/partials/footer.liquid +22 -0
- data/data/messages/partials/greeting.liquid +3 -0
- data/data/messages/partials/logo_header.liquid +18 -0
- data/data/messages/partials/signoff.liquid +1 -0
- data/data/messages/styles/v1.liquid +346 -0
- data/data/messages/templates/errors/icalendar_fetch.email.liquid +29 -0
- data/data/messages/templates/invite.email.liquid +15 -0
- data/data/messages/templates/new_customer.email.liquid +24 -0
- data/data/messages/templates/org_database_migration_finished.email.liquid +7 -0
- data/data/messages/templates/org_database_migration_started.email.liquid +9 -0
- data/data/messages/templates/specs/_field_partial.liquid +1 -0
- data/data/messages/templates/specs/basic.email.liquid +2 -0
- data/data/messages/templates/specs/basic.fake.liquid +1 -0
- data/data/messages/templates/specs/with_field.email.liquid +2 -0
- data/data/messages/templates/specs/with_field.fake.liquid +1 -0
- data/data/messages/templates/specs/with_include.email.liquid +2 -0
- data/data/messages/templates/specs/with_partial.email.liquid +1 -0
- data/data/messages/templates/verification.email.liquid +14 -0
- data/data/messages/templates/verification.sms.liquid +1 -0
- data/data/messages/web/install-customer-login.liquid +48 -0
- data/data/messages/web/install-error.liquid +17 -0
- data/data/messages/web/install-success.liquid +35 -0
- data/data/messages/web/install.liquid +20 -0
- data/data/messages/web/partials/footer.liquid +4 -0
- data/data/messages/web/partials/form_error.liquid +1 -0
- data/data/messages/web/partials/header.liquid +3 -0
- data/data/messages/web/styles.liquid +134 -0
- data/data/windows_tz.txt +461 -0
- data/db/migrations/001_testing_pixies.rb +13 -0
- data/db/migrations/002_initial.rb +132 -0
- data/db/migrations/003_ux_overhaul.rb +20 -0
- data/db/migrations/004_incremental_backfill.rb +9 -0
- data/db/migrations/005_log_webhooks.rb +24 -0
- data/db/migrations/006_generalize_roles.rb +29 -0
- data/db/migrations/007_org_dns.rb +12 -0
- data/db/migrations/008_webhook_subscriptions.rb +19 -0
- data/db/migrations/009_nonunique_stripe_subscription_customer.rb +16 -0
- data/db/migrations/010_drop_integration_soft_delete.rb +14 -0
- data/db/migrations/011_webhook_subscriptions_created_at.rb +10 -0
- data/db/migrations/012_webhook_subscriptions_created_by.rb +9 -0
- data/db/migrations/013_default_org_membership.rb +30 -0
- data/db/migrations/014_webhook_subscription_deliveries.rb +26 -0
- data/db/migrations/015_dependent_integrations.rb +9 -0
- data/db/migrations/016_encrypted_columns.rb +9 -0
- data/db/migrations/017_skip_verification.rb +9 -0
- data/db/migrations/018_sync_targets.rb +25 -0
- data/db/migrations/019_org_schema.rb +9 -0
- data/db/migrations/020_org_database_migrations.rb +25 -0
- data/db/migrations/021_no_default_org_schema.rb +14 -0
- data/db/migrations/022_database_document.rb +15 -0
- data/db/migrations/023_sync_target_schema.rb +9 -0
- data/db/migrations/024_org_semaphore_jobs.rb +9 -0
- data/db/migrations/025_integration_backfill_cursor.rb +9 -0
- data/db/migrations/026_undo_integration_backfill_cursor.rb +9 -0
- data/db/migrations/027_sync_target_http_sync.rb +12 -0
- data/db/migrations/028_logged_webhook_path.rb +24 -0
- data/db/migrations/029_encrypt_columns.rb +97 -0
- data/db/migrations/030_org_sync_target_timeout.rb +9 -0
- data/db/migrations/031_org_max_query_rows.rb +9 -0
- data/db/migrations/032_remove_db_defaults.rb +12 -0
- data/db/migrations/033_backfill_jobs.rb +26 -0
- data/db/migrations/034_backfill_job_criteria.rb +9 -0
- data/db/migrations/035_synchronous_backfill.rb +9 -0
- data/db/migrations/036_oauth.rb +26 -0
- data/db/migrations/037_oauth_used.rb +9 -0
- data/lib/amigo/durable_job.rb +416 -0
- data/lib/pry/clipboard.rb +111 -0
- data/lib/sequel/advisory_lock.rb +65 -0
- data/lib/webhookdb/admin.rb +4 -0
- data/lib/webhookdb/admin_api/auth.rb +36 -0
- data/lib/webhookdb/admin_api/customers.rb +63 -0
- data/lib/webhookdb/admin_api/database_documents.rb +20 -0
- data/lib/webhookdb/admin_api/entities.rb +66 -0
- data/lib/webhookdb/admin_api/message_deliveries.rb +61 -0
- data/lib/webhookdb/admin_api/roles.rb +15 -0
- data/lib/webhookdb/admin_api.rb +34 -0
- data/lib/webhookdb/aggregate_result.rb +63 -0
- data/lib/webhookdb/api/auth.rb +122 -0
- data/lib/webhookdb/api/connstr_auth.rb +36 -0
- data/lib/webhookdb/api/db.rb +188 -0
- data/lib/webhookdb/api/demo.rb +14 -0
- data/lib/webhookdb/api/entities.rb +198 -0
- data/lib/webhookdb/api/helpers.rb +253 -0
- data/lib/webhookdb/api/install.rb +296 -0
- data/lib/webhookdb/api/me.rb +53 -0
- data/lib/webhookdb/api/organizations.rb +254 -0
- data/lib/webhookdb/api/replay.rb +64 -0
- data/lib/webhookdb/api/service_integrations.rb +402 -0
- data/lib/webhookdb/api/services.rb +27 -0
- data/lib/webhookdb/api/stripe.rb +22 -0
- data/lib/webhookdb/api/subscriptions.rb +67 -0
- data/lib/webhookdb/api/sync_targets.rb +232 -0
- data/lib/webhookdb/api/system.rb +37 -0
- data/lib/webhookdb/api/webhook_subscriptions.rb +96 -0
- data/lib/webhookdb/api.rb +92 -0
- data/lib/webhookdb/apps.rb +93 -0
- data/lib/webhookdb/async/audit_logger.rb +38 -0
- data/lib/webhookdb/async/autoscaler.rb +84 -0
- data/lib/webhookdb/async/job.rb +18 -0
- data/lib/webhookdb/async/job_logger.rb +45 -0
- data/lib/webhookdb/async/scheduled_job.rb +18 -0
- data/lib/webhookdb/async.rb +142 -0
- data/lib/webhookdb/aws.rb +98 -0
- data/lib/webhookdb/backfill_job.rb +107 -0
- data/lib/webhookdb/backfiller.rb +107 -0
- data/lib/webhookdb/cloudflare.rb +39 -0
- data/lib/webhookdb/connection_cache.rb +177 -0
- data/lib/webhookdb/console.rb +71 -0
- data/lib/webhookdb/convertkit.rb +14 -0
- data/lib/webhookdb/crypto.rb +66 -0
- data/lib/webhookdb/customer/reset_code.rb +94 -0
- data/lib/webhookdb/customer.rb +347 -0
- data/lib/webhookdb/database_document.rb +72 -0
- data/lib/webhookdb/db_adapter/column_types.rb +37 -0
- data/lib/webhookdb/db_adapter/default_sql.rb +187 -0
- data/lib/webhookdb/db_adapter/pg.rb +96 -0
- data/lib/webhookdb/db_adapter/snowflake.rb +137 -0
- data/lib/webhookdb/db_adapter.rb +208 -0
- data/lib/webhookdb/dbutil.rb +92 -0
- data/lib/webhookdb/demo_mode.rb +100 -0
- data/lib/webhookdb/developer_alert.rb +51 -0
- data/lib/webhookdb/email_octopus.rb +21 -0
- data/lib/webhookdb/enumerable.rb +18 -0
- data/lib/webhookdb/fixtures/backfill_jobs.rb +72 -0
- data/lib/webhookdb/fixtures/customers.rb +65 -0
- data/lib/webhookdb/fixtures/database_documents.rb +27 -0
- data/lib/webhookdb/fixtures/faker.rb +41 -0
- data/lib/webhookdb/fixtures/logged_webhooks.rb +56 -0
- data/lib/webhookdb/fixtures/message_deliveries.rb +59 -0
- data/lib/webhookdb/fixtures/oauth_sessions.rb +24 -0
- data/lib/webhookdb/fixtures/organization_database_migrations.rb +37 -0
- data/lib/webhookdb/fixtures/organization_memberships.rb +54 -0
- data/lib/webhookdb/fixtures/organizations.rb +32 -0
- data/lib/webhookdb/fixtures/reset_codes.rb +23 -0
- data/lib/webhookdb/fixtures/service_integrations.rb +42 -0
- data/lib/webhookdb/fixtures/subscriptions.rb +33 -0
- data/lib/webhookdb/fixtures/sync_targets.rb +32 -0
- data/lib/webhookdb/fixtures/webhook_subscriptions.rb +35 -0
- data/lib/webhookdb/fixtures.rb +15 -0
- data/lib/webhookdb/formatting.rb +56 -0
- data/lib/webhookdb/front.rb +49 -0
- data/lib/webhookdb/github.rb +22 -0
- data/lib/webhookdb/google_calendar.rb +29 -0
- data/lib/webhookdb/heroku.rb +21 -0
- data/lib/webhookdb/http.rb +114 -0
- data/lib/webhookdb/icalendar.rb +17 -0
- data/lib/webhookdb/id.rb +17 -0
- data/lib/webhookdb/idempotency.rb +90 -0
- data/lib/webhookdb/increase.rb +42 -0
- data/lib/webhookdb/intercom.rb +23 -0
- data/lib/webhookdb/jobs/amigo_test_jobs.rb +118 -0
- data/lib/webhookdb/jobs/backfill.rb +32 -0
- data/lib/webhookdb/jobs/create_mirror_table.rb +18 -0
- data/lib/webhookdb/jobs/create_stripe_customer.rb +17 -0
- data/lib/webhookdb/jobs/customer_created_notify_internal.rb +22 -0
- data/lib/webhookdb/jobs/demo_mode_sync_data.rb +19 -0
- data/lib/webhookdb/jobs/deprecated_jobs.rb +19 -0
- data/lib/webhookdb/jobs/developer_alert_handle.rb +14 -0
- data/lib/webhookdb/jobs/durable_job_recheck_poller.rb +17 -0
- data/lib/webhookdb/jobs/emailer.rb +15 -0
- data/lib/webhookdb/jobs/icalendar_enqueue_syncs.rb +25 -0
- data/lib/webhookdb/jobs/icalendar_sync.rb +23 -0
- data/lib/webhookdb/jobs/logged_webhook_replay.rb +17 -0
- data/lib/webhookdb/jobs/logged_webhook_resilient_replay.rb +15 -0
- data/lib/webhookdb/jobs/message_dispatched.rb +16 -0
- data/lib/webhookdb/jobs/organization_database_migration_notify_finished.rb +21 -0
- data/lib/webhookdb/jobs/organization_database_migration_notify_started.rb +21 -0
- data/lib/webhookdb/jobs/organization_database_migration_run.rb +24 -0
- data/lib/webhookdb/jobs/prepare_database_connections.rb +22 -0
- data/lib/webhookdb/jobs/process_webhook.rb +47 -0
- data/lib/webhookdb/jobs/renew_watch_channel.rb +24 -0
- data/lib/webhookdb/jobs/replication_migration.rb +24 -0
- data/lib/webhookdb/jobs/reset_code_create_dispatch.rb +23 -0
- data/lib/webhookdb/jobs/scheduled_backfills.rb +77 -0
- data/lib/webhookdb/jobs/send_invite.rb +15 -0
- data/lib/webhookdb/jobs/send_test_webhook.rb +25 -0
- data/lib/webhookdb/jobs/send_webhook.rb +20 -0
- data/lib/webhookdb/jobs/sync_target_enqueue_scheduled.rb +16 -0
- data/lib/webhookdb/jobs/sync_target_run_sync.rb +38 -0
- data/lib/webhookdb/jobs/trim_logged_webhooks.rb +15 -0
- data/lib/webhookdb/jobs/webhook_resource_notify_integrations.rb +30 -0
- data/lib/webhookdb/jobs/webhook_subscription_delivery_attempt.rb +29 -0
- data/lib/webhookdb/jobs.rb +4 -0
- data/lib/webhookdb/json.rb +113 -0
- data/lib/webhookdb/liquid/expose.rb +27 -0
- data/lib/webhookdb/liquid/filters.rb +16 -0
- data/lib/webhookdb/liquid/liquification.rb +26 -0
- data/lib/webhookdb/liquid/partial.rb +12 -0
- data/lib/webhookdb/logged_webhook/resilient.rb +95 -0
- data/lib/webhookdb/logged_webhook.rb +194 -0
- data/lib/webhookdb/message/body.rb +25 -0
- data/lib/webhookdb/message/delivery.rb +127 -0
- data/lib/webhookdb/message/email_transport.rb +133 -0
- data/lib/webhookdb/message/fake_transport.rb +54 -0
- data/lib/webhookdb/message/liquid_drops.rb +29 -0
- data/lib/webhookdb/message/template.rb +89 -0
- data/lib/webhookdb/message/transport.rb +43 -0
- data/lib/webhookdb/message.rb +150 -0
- data/lib/webhookdb/messages/error_icalendar_fetch.rb +42 -0
- data/lib/webhookdb/messages/invite.rb +23 -0
- data/lib/webhookdb/messages/new_customer.rb +14 -0
- data/lib/webhookdb/messages/org_database_migration_finished.rb +23 -0
- data/lib/webhookdb/messages/org_database_migration_started.rb +24 -0
- data/lib/webhookdb/messages/specs.rb +57 -0
- data/lib/webhookdb/messages/verification.rb +23 -0
- data/lib/webhookdb/method_utilities.rb +82 -0
- data/lib/webhookdb/microsoft_calendar.rb +36 -0
- data/lib/webhookdb/nextpax.rb +14 -0
- data/lib/webhookdb/oauth/front.rb +58 -0
- data/lib/webhookdb/oauth/intercom.rb +58 -0
- data/lib/webhookdb/oauth/session.rb +24 -0
- data/lib/webhookdb/oauth.rb +80 -0
- data/lib/webhookdb/organization/alerting.rb +35 -0
- data/lib/webhookdb/organization/database_migration.rb +151 -0
- data/lib/webhookdb/organization/db_builder.rb +429 -0
- data/lib/webhookdb/organization.rb +506 -0
- data/lib/webhookdb/organization_membership.rb +58 -0
- data/lib/webhookdb/phone_number.rb +38 -0
- data/lib/webhookdb/plaid.rb +23 -0
- data/lib/webhookdb/platform.rb +27 -0
- data/lib/webhookdb/plivo.rb +52 -0
- data/lib/webhookdb/postgres/maintenance.rb +166 -0
- data/lib/webhookdb/postgres/model.rb +82 -0
- data/lib/webhookdb/postgres/model_utilities.rb +382 -0
- data/lib/webhookdb/postgres/testing_pixie.rb +16 -0
- data/lib/webhookdb/postgres/validations.rb +46 -0
- data/lib/webhookdb/postgres.rb +176 -0
- data/lib/webhookdb/postmark.rb +20 -0
- data/lib/webhookdb/redis.rb +35 -0
- data/lib/webhookdb/replicator/atom_single_feed_v1.rb +116 -0
- data/lib/webhookdb/replicator/aws_pricing_v1.rb +488 -0
- data/lib/webhookdb/replicator/base.rb +1185 -0
- data/lib/webhookdb/replicator/column.rb +482 -0
- data/lib/webhookdb/replicator/convertkit_broadcast_v1.rb +69 -0
- data/lib/webhookdb/replicator/convertkit_subscriber_v1.rb +200 -0
- data/lib/webhookdb/replicator/convertkit_tag_v1.rb +66 -0
- data/lib/webhookdb/replicator/convertkit_v1_mixin.rb +65 -0
- data/lib/webhookdb/replicator/docgen.rb +167 -0
- data/lib/webhookdb/replicator/email_octopus_campaign_v1.rb +84 -0
- data/lib/webhookdb/replicator/email_octopus_contact_v1.rb +159 -0
- data/lib/webhookdb/replicator/email_octopus_event_v1.rb +244 -0
- data/lib/webhookdb/replicator/email_octopus_list_v1.rb +101 -0
- data/lib/webhookdb/replicator/fake.rb +453 -0
- data/lib/webhookdb/replicator/front_conversation_v1.rb +45 -0
- data/lib/webhookdb/replicator/front_marketplace_root_v1.rb +55 -0
- data/lib/webhookdb/replicator/front_message_v1.rb +45 -0
- data/lib/webhookdb/replicator/front_v1_mixin.rb +22 -0
- data/lib/webhookdb/replicator/github_issue_comment_v1.rb +58 -0
- data/lib/webhookdb/replicator/github_issue_v1.rb +83 -0
- data/lib/webhookdb/replicator/github_pull_v1.rb +84 -0
- data/lib/webhookdb/replicator/github_release_v1.rb +47 -0
- data/lib/webhookdb/replicator/github_repo_v1_mixin.rb +250 -0
- data/lib/webhookdb/replicator/github_repository_event_v1.rb +45 -0
- data/lib/webhookdb/replicator/icalendar_calendar_v1.rb +465 -0
- data/lib/webhookdb/replicator/icalendar_event_v1.rb +334 -0
- data/lib/webhookdb/replicator/increase_account_number_v1.rb +77 -0
- data/lib/webhookdb/replicator/increase_account_transfer_v1.rb +61 -0
- data/lib/webhookdb/replicator/increase_account_v1.rb +63 -0
- data/lib/webhookdb/replicator/increase_ach_transfer_v1.rb +78 -0
- data/lib/webhookdb/replicator/increase_check_transfer_v1.rb +64 -0
- data/lib/webhookdb/replicator/increase_limit_v1.rb +78 -0
- data/lib/webhookdb/replicator/increase_transaction_v1.rb +74 -0
- data/lib/webhookdb/replicator/increase_v1_mixin.rb +121 -0
- data/lib/webhookdb/replicator/increase_wire_transfer_v1.rb +61 -0
- data/lib/webhookdb/replicator/intercom_contact_v1.rb +36 -0
- data/lib/webhookdb/replicator/intercom_conversation_v1.rb +38 -0
- data/lib/webhookdb/replicator/intercom_marketplace_root_v1.rb +69 -0
- data/lib/webhookdb/replicator/intercom_v1_mixin.rb +105 -0
- data/lib/webhookdb/replicator/oauth_refresh_access_token_mixin.rb +65 -0
- data/lib/webhookdb/replicator/plivo_sms_inbound_v1.rb +102 -0
- data/lib/webhookdb/replicator/postmark_inbound_message_v1.rb +94 -0
- data/lib/webhookdb/replicator/postmark_outbound_message_event_v1.rb +107 -0
- data/lib/webhookdb/replicator/schema_modification.rb +42 -0
- data/lib/webhookdb/replicator/shopify_customer_v1.rb +58 -0
- data/lib/webhookdb/replicator/shopify_order_v1.rb +64 -0
- data/lib/webhookdb/replicator/shopify_v1_mixin.rb +161 -0
- data/lib/webhookdb/replicator/signalwire_message_v1.rb +169 -0
- data/lib/webhookdb/replicator/sponsy_customer_v1.rb +54 -0
- data/lib/webhookdb/replicator/sponsy_placement_v1.rb +34 -0
- data/lib/webhookdb/replicator/sponsy_publication_v1.rb +125 -0
- data/lib/webhookdb/replicator/sponsy_slot_v1.rb +41 -0
- data/lib/webhookdb/replicator/sponsy_status_v1.rb +35 -0
- data/lib/webhookdb/replicator/sponsy_v1_mixin.rb +165 -0
- data/lib/webhookdb/replicator/state_machine_step.rb +69 -0
- data/lib/webhookdb/replicator/stripe_charge_v1.rb +77 -0
- data/lib/webhookdb/replicator/stripe_coupon_v1.rb +62 -0
- data/lib/webhookdb/replicator/stripe_customer_v1.rb +60 -0
- data/lib/webhookdb/replicator/stripe_dispute_v1.rb +77 -0
- data/lib/webhookdb/replicator/stripe_invoice_item_v1.rb +82 -0
- data/lib/webhookdb/replicator/stripe_invoice_v1.rb +116 -0
- data/lib/webhookdb/replicator/stripe_payout_v1.rb +67 -0
- data/lib/webhookdb/replicator/stripe_price_v1.rb +60 -0
- data/lib/webhookdb/replicator/stripe_product_v1.rb +60 -0
- data/lib/webhookdb/replicator/stripe_refund_v1.rb +101 -0
- data/lib/webhookdb/replicator/stripe_subscription_item_v1.rb +56 -0
- data/lib/webhookdb/replicator/stripe_subscription_v1.rb +75 -0
- data/lib/webhookdb/replicator/stripe_v1_mixin.rb +116 -0
- data/lib/webhookdb/replicator/transistor_episode_stats_v1.rb +141 -0
- data/lib/webhookdb/replicator/transistor_episode_v1.rb +169 -0
- data/lib/webhookdb/replicator/transistor_show_v1.rb +68 -0
- data/lib/webhookdb/replicator/transistor_v1_mixin.rb +65 -0
- data/lib/webhookdb/replicator/twilio_sms_v1.rb +156 -0
- data/lib/webhookdb/replicator/webhook_request.rb +5 -0
- data/lib/webhookdb/replicator/webhookdb_customer_v1.rb +74 -0
- data/lib/webhookdb/replicator.rb +224 -0
- data/lib/webhookdb/role.rb +42 -0
- data/lib/webhookdb/sentry.rb +35 -0
- data/lib/webhookdb/service/auth.rb +138 -0
- data/lib/webhookdb/service/collection.rb +91 -0
- data/lib/webhookdb/service/entities.rb +97 -0
- data/lib/webhookdb/service/helpers.rb +270 -0
- data/lib/webhookdb/service/middleware.rb +124 -0
- data/lib/webhookdb/service/types.rb +30 -0
- data/lib/webhookdb/service/validators.rb +32 -0
- data/lib/webhookdb/service/view_api.rb +63 -0
- data/lib/webhookdb/service.rb +219 -0
- data/lib/webhookdb/service_integration.rb +332 -0
- data/lib/webhookdb/shopify.rb +35 -0
- data/lib/webhookdb/signalwire.rb +13 -0
- data/lib/webhookdb/slack.rb +68 -0
- data/lib/webhookdb/snowflake.rb +90 -0
- data/lib/webhookdb/spec_helpers/async.rb +122 -0
- data/lib/webhookdb/spec_helpers/citest.rb +88 -0
- data/lib/webhookdb/spec_helpers/integration.rb +121 -0
- data/lib/webhookdb/spec_helpers/message.rb +41 -0
- data/lib/webhookdb/spec_helpers/postgres.rb +220 -0
- data/lib/webhookdb/spec_helpers/service.rb +432 -0
- data/lib/webhookdb/spec_helpers/shared_examples_for_columns.rb +56 -0
- data/lib/webhookdb/spec_helpers/shared_examples_for_replicators.rb +915 -0
- data/lib/webhookdb/spec_helpers/whdb.rb +139 -0
- data/lib/webhookdb/spec_helpers.rb +63 -0
- data/lib/webhookdb/sponsy.rb +14 -0
- data/lib/webhookdb/stripe.rb +37 -0
- data/lib/webhookdb/subscription.rb +203 -0
- data/lib/webhookdb/sync_target.rb +491 -0
- data/lib/webhookdb/tasks/admin.rb +49 -0
- data/lib/webhookdb/tasks/annotate.rb +36 -0
- data/lib/webhookdb/tasks/db.rb +82 -0
- data/lib/webhookdb/tasks/docs.rb +42 -0
- data/lib/webhookdb/tasks/fixture.rb +35 -0
- data/lib/webhookdb/tasks/message.rb +50 -0
- data/lib/webhookdb/tasks/regress.rb +87 -0
- data/lib/webhookdb/tasks/release.rb +27 -0
- data/lib/webhookdb/tasks/sidekiq.rb +23 -0
- data/lib/webhookdb/tasks/specs.rb +64 -0
- data/lib/webhookdb/theranest.rb +15 -0
- data/lib/webhookdb/transistor.rb +13 -0
- data/lib/webhookdb/twilio.rb +13 -0
- data/lib/webhookdb/typed_struct.rb +44 -0
- data/lib/webhookdb/version.rb +5 -0
- data/lib/webhookdb/webhook_response.rb +50 -0
- data/lib/webhookdb/webhook_subscription/delivery.rb +82 -0
- data/lib/webhookdb/webhook_subscription.rb +226 -0
- data/lib/webhookdb/windows_tz.rb +32 -0
- data/lib/webhookdb/xml.rb +92 -0
- data/lib/webhookdb.rb +224 -0
- data/lib/webterm/apps.rb +45 -0
- metadata +1129 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape_entity"
|
|
4
|
+
|
|
5
|
+
require "webhookdb/service/entities"
|
|
6
|
+
require "webhookdb/api" unless defined? Webhookdb::API
|
|
7
|
+
|
|
8
|
+
module Webhookdb::API
|
|
9
|
+
MoneyEntity = Webhookdb::Service::Entities::Money
|
|
10
|
+
TimeRangeEntity = Webhookdb::Service::Entities::TimeRange
|
|
11
|
+
|
|
12
|
+
class BaseEntity < Webhookdb::Service::Entities::Base; end
|
|
13
|
+
|
|
14
|
+
class OrganizationEntity < BaseEntity
|
|
15
|
+
expose :id
|
|
16
|
+
expose :name
|
|
17
|
+
expose :key
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class OrganizationMembershipEntity < BaseEntity
|
|
21
|
+
expose :customer_email, as: :email
|
|
22
|
+
expose :organization, with: OrganizationEntity
|
|
23
|
+
expose :organization_name, &self.delegate_to(:organization, :name)
|
|
24
|
+
expose :organization_key, &self.delegate_to(:organization, :key)
|
|
25
|
+
expose :status
|
|
26
|
+
|
|
27
|
+
def self.display_headers
|
|
28
|
+
return [
|
|
29
|
+
[:email, "Email"],
|
|
30
|
+
[:organization_name, "Organization Name"],
|
|
31
|
+
[:organization_key, "Organization Key"],
|
|
32
|
+
[:status, "Role"],
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class CurrentCustomerEntity < BaseEntity
|
|
38
|
+
expose :email
|
|
39
|
+
expose :name
|
|
40
|
+
expose :default_organization, with: OrganizationEntity
|
|
41
|
+
expose :default_organization_formatted,
|
|
42
|
+
&self.delegate_to(:default_organization, :display_string, safe_with_default: "")
|
|
43
|
+
expose :verified_memberships, with: OrganizationMembershipEntity
|
|
44
|
+
expose :verified_memberships_formatted do |instance|
|
|
45
|
+
lines = instance.verified_memberships.map { |m| "#{m.organization.display_string}: #{m.status}" }
|
|
46
|
+
lines.join("\n")
|
|
47
|
+
end
|
|
48
|
+
expose :invited_memberships, as: :invitations, with: OrganizationMembershipEntity
|
|
49
|
+
expose :invitations_formatted do |instance|
|
|
50
|
+
lines = instance.invited_memberships.map { |m| "#{m.organization.display_string}: #{m.invitation_code}" }
|
|
51
|
+
lines.join("\n")
|
|
52
|
+
end
|
|
53
|
+
expose :display_headers do |_|
|
|
54
|
+
[
|
|
55
|
+
[:email, "Email"],
|
|
56
|
+
[:default_organization_formatted, "Default Org"],
|
|
57
|
+
[:verified_memberships_formatted, "Memberships"],
|
|
58
|
+
[:invitations_formatted, "Invitations"],
|
|
59
|
+
]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class ServiceIntegrationEntity < BaseEntity
|
|
64
|
+
expose :opaque_id
|
|
65
|
+
expose :service_name
|
|
66
|
+
expose :table_name
|
|
67
|
+
|
|
68
|
+
def self.display_headers
|
|
69
|
+
return [[:service_name, "Name"], [:table_name, "Table"], [:opaque_id, "Id"]]
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
class ServiceEntity < BaseEntity
|
|
74
|
+
expose :name
|
|
75
|
+
|
|
76
|
+
def self.display_headers
|
|
77
|
+
return [[:name, "Name"]]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
class StateMachineEntity < BaseEntity
|
|
82
|
+
expose :needs_input
|
|
83
|
+
expose :prompt
|
|
84
|
+
expose :prompt_is_secret
|
|
85
|
+
expose :post_to_url
|
|
86
|
+
expose :post_params
|
|
87
|
+
expose :post_params_value_key
|
|
88
|
+
expose :complete
|
|
89
|
+
expose :output
|
|
90
|
+
expose :error_code
|
|
91
|
+
expose :extras do |_, opts|
|
|
92
|
+
opts[:extras] || {}
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class SubscriptionPlanEntity < BaseEntity
|
|
97
|
+
expose :key
|
|
98
|
+
expose :description
|
|
99
|
+
expose :price, with: MoneyEntity
|
|
100
|
+
expose :price_formatted, &self.delegate_to(:price, :format)
|
|
101
|
+
|
|
102
|
+
def self.display_headers
|
|
103
|
+
return [[:key, "Key"], [:description, "Description"], [:price_formatted, "Price"]]
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class WebhookSubscriptionEntity < BaseEntity
|
|
108
|
+
expose :created_at
|
|
109
|
+
expose :opaque_id
|
|
110
|
+
expose :deliver_to_url
|
|
111
|
+
expose :organization, with: OrganizationEntity
|
|
112
|
+
expose :service_integration, with: ServiceIntegrationEntity
|
|
113
|
+
expose :associated_type
|
|
114
|
+
expose :associated_id
|
|
115
|
+
expose :status
|
|
116
|
+
|
|
117
|
+
def self.display_headers
|
|
118
|
+
return [
|
|
119
|
+
[:opaque_id, "Id"],
|
|
120
|
+
[:deliver_to_url, "Url"],
|
|
121
|
+
[:status, "Status"],
|
|
122
|
+
[:associated_type, "Associated Type"],
|
|
123
|
+
[:associated_id, "Associated Id"],
|
|
124
|
+
]
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
class BaseSyncTargetEntity < BaseEntity
|
|
129
|
+
expose :created_at
|
|
130
|
+
expose :opaque_id
|
|
131
|
+
expose :service_integration, with: ServiceIntegrationEntity
|
|
132
|
+
expose :period_seconds
|
|
133
|
+
expose :displaysafe_connection_url, as: :connection_url
|
|
134
|
+
expose :table
|
|
135
|
+
expose :schema
|
|
136
|
+
expose :last_synced_at
|
|
137
|
+
expose :associated_type
|
|
138
|
+
expose :associated_id
|
|
139
|
+
expose :associated_object_display
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
class DbSyncTargetEntity < BaseSyncTargetEntity
|
|
143
|
+
expose :schema_and_table_string
|
|
144
|
+
|
|
145
|
+
def self.display_headers
|
|
146
|
+
return [
|
|
147
|
+
[:opaque_id, "Id"],
|
|
148
|
+
[:connection_url, "URL"],
|
|
149
|
+
[:associated_object_display, "Associated"],
|
|
150
|
+
[:schema_and_table_string, "Table"],
|
|
151
|
+
[:last_synced_at, "Last Synced"],
|
|
152
|
+
[:period_seconds, "Period"],
|
|
153
|
+
[:page_size, "Page"],
|
|
154
|
+
]
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
class HttpSyncTargetEntity < BaseSyncTargetEntity
|
|
159
|
+
def self.display_headers
|
|
160
|
+
return [
|
|
161
|
+
[:opaque_id, "Id"],
|
|
162
|
+
[:connection_url, "URL"],
|
|
163
|
+
[:associated_object_display, "Associated"],
|
|
164
|
+
[:last_synced_at, "Last Synced"],
|
|
165
|
+
[:period_seconds, "Period"],
|
|
166
|
+
[:page_size, "Page"],
|
|
167
|
+
]
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class DatabaseMigrationEntity < BaseEntity
|
|
172
|
+
expose :created_at
|
|
173
|
+
expose :started_at
|
|
174
|
+
expose :finished_at
|
|
175
|
+
expose :displaysafe_source_url, as: :source_url
|
|
176
|
+
expose :displaysafe_destination_url, as: :destination_url
|
|
177
|
+
expose :status
|
|
178
|
+
|
|
179
|
+
def self.display_headers
|
|
180
|
+
return [
|
|
181
|
+
[:created_at, "Created at"],
|
|
182
|
+
[:started_at, "Started at"],
|
|
183
|
+
[:finished_at, "Finished at"],
|
|
184
|
+
[:source_url, "Source"],
|
|
185
|
+
[:destination_url, "Destination"],
|
|
186
|
+
[:status, "Status"],
|
|
187
|
+
]
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
class BackfillJobEntity < BaseEntity
|
|
192
|
+
expose :opaque_id, as: :id
|
|
193
|
+
expose :status
|
|
194
|
+
expose :started_at
|
|
195
|
+
expose :fully_finished_at, as: :finished_at
|
|
196
|
+
expose :service_integration, with: ServiceIntegrationEntity
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
require "webhookdb/demo_mode"
|
|
5
|
+
require "webhookdb/jobs/process_webhook"
|
|
6
|
+
|
|
7
|
+
module Webhookdb::API::Helpers
|
|
8
|
+
extend Grape::API::Helpers
|
|
9
|
+
|
|
10
|
+
# Prompt for input given some criteria.
|
|
11
|
+
#
|
|
12
|
+
# NOTE: You cannot use :prompt with 'requires', or 'allow_blank'.
|
|
13
|
+
# You MUST use 'optional', and not specify allow_blank
|
|
14
|
+
# (validation will error if these conditions are not met).
|
|
15
|
+
# The semantics around prompts are too subtle to use these built-in validators;
|
|
16
|
+
# we must use our own.
|
|
17
|
+
# Note also, while :default will not error (because we cannot detect it easily),
|
|
18
|
+
# it should not be used since it defeats the purpose of :prompt.
|
|
19
|
+
#
|
|
20
|
+
# The main complexity is around optional params
|
|
21
|
+
# that will take a given default if blank (but we need to prompt if not supplied),
|
|
22
|
+
# or 'enter to confirm' type prompts, where we want to prompt if not supplied.
|
|
23
|
+
#
|
|
24
|
+
# To handle these cases, use the :optional and :confirm options, as below.
|
|
25
|
+
# On the Go client, use string pointers for these values, with omitempty;
|
|
26
|
+
# they will still submit an empty string, but will not include the key if nil.
|
|
27
|
+
#
|
|
28
|
+
# Examples:
|
|
29
|
+
#
|
|
30
|
+
# requires :param, prompt: "Enter a value:"
|
|
31
|
+
#
|
|
32
|
+
# This is by far the most common usage.
|
|
33
|
+
# If :param is not present (ie, `params[:param].present?` is falsy),
|
|
34
|
+
# a 422 is returned with a StateMachineStep with a prompt value of 'Enter a value:'.
|
|
35
|
+
#
|
|
36
|
+
# All other forms use a Hash instead of a string as the argument.
|
|
37
|
+
#
|
|
38
|
+
# requires :param, prompt: {message: 'Enter secret:', secret: true}
|
|
39
|
+
#
|
|
40
|
+
# Same as above, but the prompt is set to be a secret.
|
|
41
|
+
#
|
|
42
|
+
# requires :param, prompt: {message: 'Press Enter to confirm, or Ctrl+C to cancel:', confirm: true}
|
|
43
|
+
#
|
|
44
|
+
# This will 422 if :param is not provided or is nil;
|
|
45
|
+
# it will pass otherwise (so empty values, like '' or false, are valid).
|
|
46
|
+
# This is used to guard against actions that need confirmation.
|
|
47
|
+
# Note that in many situations, we don't know about the need to confirm
|
|
48
|
+
# until we're into the body of the endpoint. In these cases,
|
|
49
|
+
# use `Webhookdb::API::Helpers.prompt_for_required_param!` directly,
|
|
50
|
+
# along with something like `optional :param`.
|
|
51
|
+
#
|
|
52
|
+
# requires :param, prompt: {message: 'This will default', optional: true}
|
|
53
|
+
#
|
|
54
|
+
# This will 422 if not provided, but will pass otherwise
|
|
55
|
+
# (so nil, '', and false are all valid values).
|
|
56
|
+
#
|
|
57
|
+
# optional :param, prompt: {message: 'Bypassable', disable: ->(req) { req.env['HTTP_NOPROMPT']} }
|
|
58
|
+
#
|
|
59
|
+
# This will disable the prompt behavior if the proc given to :disable returns true.
|
|
60
|
+
# This is mostly useful when we want to avoid prompting for something
|
|
61
|
+
# because the endpoint is going to have some particular behavior that will avoid the purpose of the prompt.
|
|
62
|
+
#
|
|
63
|
+
class Prompt < ::Grape::Validations::Validators::Base
|
|
64
|
+
def validate(request)
|
|
65
|
+
raise "allow_blank must not be set" unless @allow_blank.nil?
|
|
66
|
+
attr_name = @attrs.first
|
|
67
|
+
if @option.is_a?(String)
|
|
68
|
+
options = {message: @option}
|
|
69
|
+
else
|
|
70
|
+
options = @option
|
|
71
|
+
raise "Missing :message key in prompt args" unless options[:message]
|
|
72
|
+
end
|
|
73
|
+
raise "must use optional for #{attr_name}" if @required
|
|
74
|
+
return unless self.needs_prompt?(attr_name, request, options)
|
|
75
|
+
Webhookdb::API::Helpers.prompt_for_required_param!(
|
|
76
|
+
request,
|
|
77
|
+
attr_name,
|
|
78
|
+
options[:message],
|
|
79
|
+
secret: options[:secret] || false,
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
protected def needs_prompt?(attr_name, request, options)
|
|
84
|
+
if (disable_proc = options[:disable]) && (disable_proc[request])
|
|
85
|
+
return false
|
|
86
|
+
end
|
|
87
|
+
options[:demo_mode_proc][request] if Webhookdb::DemoMode.client_enabled? && options[:demo_mode_proc]
|
|
88
|
+
params = request.params
|
|
89
|
+
if options[:confirm]
|
|
90
|
+
return true unless params.key?(attr_name)
|
|
91
|
+
return true if params[attr_name].nil?
|
|
92
|
+
return false
|
|
93
|
+
end
|
|
94
|
+
if options[:optional]
|
|
95
|
+
return true unless params.key?(attr_name)
|
|
96
|
+
return false
|
|
97
|
+
end
|
|
98
|
+
value = params[attr_name]
|
|
99
|
+
return false if value.present?
|
|
100
|
+
return false if value.is_a?(FalseClass)
|
|
101
|
+
return true
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.prompt_for_required_param!(request, key, prompt, secret: false, output: "")
|
|
106
|
+
step = Webhookdb::Replicator::StateMachineStep.new
|
|
107
|
+
step.output = output
|
|
108
|
+
step.post_to_url = request.path
|
|
109
|
+
step.post_params = request.params.to_h
|
|
110
|
+
step.post_params_value_key = key
|
|
111
|
+
step.set_prompt(prompt, secret:)
|
|
112
|
+
body = Webhookdb::Service.error_body(
|
|
113
|
+
422,
|
|
114
|
+
"Prompt for required params",
|
|
115
|
+
code: "prompt_required_params",
|
|
116
|
+
more: {state_machine_step: Webhookdb::API::StateMachineEntity.represent(step)},
|
|
117
|
+
)
|
|
118
|
+
throw :error, message: body, status: 422, headers: {"Whdb-Prompt" => key.to_s}
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def lookup_service_integration!(org, identifier)
|
|
122
|
+
sints = org.service_integrations_dataset.
|
|
123
|
+
where(Sequel[service_name: identifier] | Sequel[table_name: identifier] | Sequel[opaque_id: identifier]).
|
|
124
|
+
limit(2).all
|
|
125
|
+
return sints.first if sints.size == 1
|
|
126
|
+
merror!(403, "There is no service integration with that identifier.") if sints.empty?
|
|
127
|
+
dupe_attr = nil
|
|
128
|
+
alternative = nil
|
|
129
|
+
if sints.first.service_name == identifier
|
|
130
|
+
dupe_attr = "service name"
|
|
131
|
+
alternative = "table name"
|
|
132
|
+
else
|
|
133
|
+
dupe_attr = "table name"
|
|
134
|
+
alternative = "service name"
|
|
135
|
+
end
|
|
136
|
+
msg403 = "There are multiple integrations with that #{dupe_attr}. " \
|
|
137
|
+
"Try again using an integration id, or a #{alternative}. " \
|
|
138
|
+
"Use `webhookdb integrations list` to see all integrations."
|
|
139
|
+
merror!(409, msg403)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Our primary webhook endpoint is /v1/service_integrations/<opaque_id>,
|
|
143
|
+
# but in some cases we need a 'static' endpoint for apps to send to,
|
|
144
|
+
# like /v1/install/front/webhooks.
|
|
145
|
+
# Those endpoints share the webhook handling behavior with this method.
|
|
146
|
+
#
|
|
147
|
+
# The block passed to this method yields the service integration.
|
|
148
|
+
# This is important because we want to make sure to log the webhook if something goes wrong
|
|
149
|
+
# while looking up the service integration.
|
|
150
|
+
#
|
|
151
|
+
# The potential_opaque_id should be a way to identify who is responsible for
|
|
152
|
+
# the webhook request. For example, to `/v1/service_integrations/svi_abc`,
|
|
153
|
+
# this would be `svi_abc` (even though it's an invalid opaque id).
|
|
154
|
+
# In other cases, especially marketplace integrations, this could be some other value
|
|
155
|
+
# to identify the webhook that was sent.
|
|
156
|
+
#
|
|
157
|
+
# If the block yields the Symbol :pass, no further handling is done;
|
|
158
|
+
# this would be done for example when there is no valid service integration.
|
|
159
|
+
# Otherwise, the block must yield a service integration.
|
|
160
|
+
def handle_webhook_request(potential_opaque_id, &)
|
|
161
|
+
opaque_id = potential_opaque_id
|
|
162
|
+
organization_id = nil
|
|
163
|
+
s_status = nil
|
|
164
|
+
request_headers = {}
|
|
165
|
+
raise LocalJumpError unless block_given?
|
|
166
|
+
begin
|
|
167
|
+
sint = yield
|
|
168
|
+
return if sint == :pass
|
|
169
|
+
raise "error instead of return nil if there is no service integration" if sint.nil?
|
|
170
|
+
opaque_id = sint.opaque_id
|
|
171
|
+
organization_id = sint.organization_id
|
|
172
|
+
request_headers = request.headers.dup
|
|
173
|
+
if (content_type = env["CONTENT_TYPE"])
|
|
174
|
+
request_headers["Content-Type"] = content_type
|
|
175
|
+
end
|
|
176
|
+
svc = Webhookdb::Replicator.create(sint).dispatch_request_to(request)
|
|
177
|
+
svc.preprocess_headers_for_logging(request_headers)
|
|
178
|
+
handling_sint = svc.service_integration
|
|
179
|
+
whresp = svc.webhook_response(request)
|
|
180
|
+
s_status, s_headers, s_body = whresp.to_rack
|
|
181
|
+
(s_status = 200) if s_status >= 400 && Webhookdb.regression_mode?
|
|
182
|
+
|
|
183
|
+
if s_status >= 400
|
|
184
|
+
logger.warn "rejected_webhook", webhook_headers: request_headers, webhook_body: env["api.request.body"]
|
|
185
|
+
header "Whdb-Rejected-Reason", whresp.reason
|
|
186
|
+
else
|
|
187
|
+
req_body = env.key?("api.request.body") ? env["api.request.body"] : env["rack.input"].read
|
|
188
|
+
req_body = {} if req_body.blank?
|
|
189
|
+
process_kwargs = {
|
|
190
|
+
headers: request_headers,
|
|
191
|
+
body: req_body,
|
|
192
|
+
request_path: request.path_info,
|
|
193
|
+
request_method: request.request_method,
|
|
194
|
+
}
|
|
195
|
+
event_json = Amigo::Event.create(
|
|
196
|
+
"webhookdb.serviceintegration.webhook", [handling_sint.id, process_kwargs],
|
|
197
|
+
).as_json
|
|
198
|
+
# Audit Log this synchronously.
|
|
199
|
+
# It should be fast enough. We may as well log here so we can avoid
|
|
200
|
+
# serializing the (large) webhook payload multiple times, as with normal pubsub.
|
|
201
|
+
Webhookdb::Async::AuditLogger.new.perform(event_json)
|
|
202
|
+
if svc.process_webhooks_synchronously? || Webhookdb::Replicator.always_process_synchronously
|
|
203
|
+
whreq = Webhookdb::Replicator::WebhookRequest.new(
|
|
204
|
+
method: process_kwargs[:request_method],
|
|
205
|
+
path: process_kwargs[:request_path],
|
|
206
|
+
headers: process_kwargs[:headers],
|
|
207
|
+
body: process_kwargs[:body],
|
|
208
|
+
)
|
|
209
|
+
inserted = svc.upsert_webhook(whreq)
|
|
210
|
+
s_body = svc.synchronous_processing_response_body(upserted: inserted, request: whreq)
|
|
211
|
+
else
|
|
212
|
+
queue = svc.upsert_has_deps? ? "netout" : "webhook"
|
|
213
|
+
Webhookdb::Jobs::ProcessWebhook.set(queue:).perform_async(event_json)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
s_headers.each { |k, v| header k, v }
|
|
218
|
+
if s_headers["Content-Type"] == "application/json"
|
|
219
|
+
body Oj.load(s_body)
|
|
220
|
+
else
|
|
221
|
+
env["api.format"] = :binary
|
|
222
|
+
body s_body
|
|
223
|
+
end
|
|
224
|
+
status s_status
|
|
225
|
+
ensure
|
|
226
|
+
_log_webhook_request(opaque_id, organization_id, s_status, request_headers)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def _log_webhook_request(opaque_id, organization_id, sstatus, request_headers)
|
|
231
|
+
return if request.headers[Webhookdb::LoggedWebhook::RETRY_HEADER]
|
|
232
|
+
# Status can be set from:
|
|
233
|
+
# - the 'status' method, which will be 201 if it hasn't been set,
|
|
234
|
+
# or another value if it has been set.
|
|
235
|
+
# - the webhook responder, which could respond with 401, etc
|
|
236
|
+
# - if there was an exception- so no status is set yet- use 0
|
|
237
|
+
# The main thing to watch out for is that we:
|
|
238
|
+
# - Cannot assume an exception is a 500 (it can be rescued later)
|
|
239
|
+
# - Must handle error! calls
|
|
240
|
+
# Anyway, this is all pretty confusing, but it's all tested.
|
|
241
|
+
rstatus = status == 201 ? (sstatus || 0) : status
|
|
242
|
+
request.body.rewind
|
|
243
|
+
Webhookdb::LoggedWebhook.resilient_insert(
|
|
244
|
+
request_body: request.body.read,
|
|
245
|
+
request_headers: request_headers.to_json,
|
|
246
|
+
request_method: request.request_method,
|
|
247
|
+
request_path: request.path_info,
|
|
248
|
+
response_status: rstatus,
|
|
249
|
+
organization_id:,
|
|
250
|
+
service_integration_opaque_id: opaque_id,
|
|
251
|
+
)
|
|
252
|
+
end
|
|
253
|
+
end
|