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,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/github"
|
|
4
|
+
require "webhookdb/replicator/github_repo_v1_mixin"
|
|
5
|
+
|
|
6
|
+
class Webhookdb::Replicator::GithubIssueV1 < Webhookdb::Replicator::Base
|
|
7
|
+
include Appydays::Loggable
|
|
8
|
+
include Webhookdb::Replicator::GithubRepoV1Mixin
|
|
9
|
+
|
|
10
|
+
def _mixin_backfill_url = "/issues"
|
|
11
|
+
def _mixin_webhook_events = ["Issues"]
|
|
12
|
+
def _mixin_webhook_key = "issue"
|
|
13
|
+
def _mixin_fine_grained_permission = "Issues"
|
|
14
|
+
def _mixin_fetch_resource_if_field_missing = "closed_by"
|
|
15
|
+
|
|
16
|
+
def _mixin_query_params(last_backfilled:)
|
|
17
|
+
q = {state: "all"}
|
|
18
|
+
if last_backfilled
|
|
19
|
+
q[:sort] = "updated"
|
|
20
|
+
q[:since] = last_backfilled.utc.iso8601
|
|
21
|
+
end
|
|
22
|
+
return q
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Webhookdb::Replicator::Descriptor]
|
|
26
|
+
def self.descriptor
|
|
27
|
+
return Webhookdb::Replicator::Descriptor.new(
|
|
28
|
+
name: "github_issue_v1",
|
|
29
|
+
ctor: ->(sint) { Webhookdb::Replicator::GithubIssueV1.new(sint) },
|
|
30
|
+
feature_roles: [],
|
|
31
|
+
resource_name_singular: "GitHub Issue",
|
|
32
|
+
supports_webhooks: true,
|
|
33
|
+
supports_backfill: true,
|
|
34
|
+
api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/issues/issues"),
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def _remote_key_column
|
|
39
|
+
return Webhookdb::Replicator::Column.new(:github_id, BIGINT, data_key: "id")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def _denormalized_columns
|
|
43
|
+
return [
|
|
44
|
+
Webhookdb::Replicator::Column.new(:node_id, TEXT, index: true),
|
|
45
|
+
Webhookdb::Replicator::Column.new(:number, INTEGER, index: true),
|
|
46
|
+
Webhookdb::Replicator::Column.new(:state, TEXT),
|
|
47
|
+
Webhookdb::Replicator::Column.new(:user_id, BIGINT, index: true, data_key: ["user", "id"], optional: true),
|
|
48
|
+
Webhookdb::Replicator::Column.new(
|
|
49
|
+
:closed_by_id,
|
|
50
|
+
BIGINT,
|
|
51
|
+
index: true,
|
|
52
|
+
data_key: ["closed_by", "id"],
|
|
53
|
+
optional: true,
|
|
54
|
+
),
|
|
55
|
+
Webhookdb::Replicator::Column.new(
|
|
56
|
+
:assignee_ids,
|
|
57
|
+
BIGINT_ARRAY,
|
|
58
|
+
index: true,
|
|
59
|
+
data_key: "assignees",
|
|
60
|
+
optional: true,
|
|
61
|
+
converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
|
|
62
|
+
),
|
|
63
|
+
Webhookdb::Replicator::Column.new(
|
|
64
|
+
:milestone_number,
|
|
65
|
+
INTEGER,
|
|
66
|
+
data_key: ["milestone", "number"],
|
|
67
|
+
optional: true,
|
|
68
|
+
),
|
|
69
|
+
Webhookdb::Replicator::Column.new(
|
|
70
|
+
:label_ids,
|
|
71
|
+
BIGINT_ARRAY,
|
|
72
|
+
data_key: "labels",
|
|
73
|
+
optional: true,
|
|
74
|
+
converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
|
|
75
|
+
),
|
|
76
|
+
Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
|
|
77
|
+
Webhookdb::Replicator::Column.new(:closed_at, TIMESTAMP, index: true),
|
|
78
|
+
Webhookdb::Replicator::Column.new(:updated_at, TIMESTAMP, index: true),
|
|
79
|
+
]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def _timestamp_column_name = :updated_at
|
|
83
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/github"
|
|
4
|
+
require "webhookdb/replicator/github_repo_v1_mixin"
|
|
5
|
+
|
|
6
|
+
class Webhookdb::Replicator::GithubPullV1 < Webhookdb::Replicator::Base
|
|
7
|
+
include Appydays::Loggable
|
|
8
|
+
include Webhookdb::Replicator::GithubRepoV1Mixin
|
|
9
|
+
|
|
10
|
+
def _mixin_backfill_url = "/pulls"
|
|
11
|
+
def _mixin_webhook_events = ["Pull requests"]
|
|
12
|
+
def _mixin_webhook_key = "pull_request"
|
|
13
|
+
def _mixin_fine_grained_permission = "Pull requests"
|
|
14
|
+
def _mixin_fetch_resource_if_field_missing = "merged_by"
|
|
15
|
+
|
|
16
|
+
def _mixin_query_params(last_backfilled:)
|
|
17
|
+
q = {state: "all"}
|
|
18
|
+
if last_backfilled
|
|
19
|
+
q[:sort] = "updated"
|
|
20
|
+
q[:since] = last_backfilled.utc.iso8601
|
|
21
|
+
end
|
|
22
|
+
return q
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Webhookdb::Replicator::Descriptor]
|
|
26
|
+
def self.descriptor
|
|
27
|
+
return Webhookdb::Replicator::Descriptor.new(
|
|
28
|
+
name: "github_pull_v1",
|
|
29
|
+
ctor: ->(sint) { Webhookdb::Replicator::GithubPullV1.new(sint) },
|
|
30
|
+
feature_roles: [],
|
|
31
|
+
resource_name_singular: "GitHub Pull Request",
|
|
32
|
+
supports_webhooks: true,
|
|
33
|
+
supports_backfill: true,
|
|
34
|
+
api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/pulls/pulls"),
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def _remote_key_column
|
|
39
|
+
return Webhookdb::Replicator::Column.new(:github_id, BIGINT, data_key: "id")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def _denormalized_columns
|
|
43
|
+
return [
|
|
44
|
+
Webhookdb::Replicator::Column.new(:number, INTEGER, index: true),
|
|
45
|
+
Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
|
|
46
|
+
Webhookdb::Replicator::Column.new(:updated_at, TIMESTAMP, index: true),
|
|
47
|
+
Webhookdb::Replicator::Column.new(:closed_at, TIMESTAMP, index: true, optional: true),
|
|
48
|
+
Webhookdb::Replicator::Column.new(:merged_at, TIMESTAMP, index: true, optional: true),
|
|
49
|
+
Webhookdb::Replicator::Column.new(:state, TEXT),
|
|
50
|
+
Webhookdb::Replicator::Column.new(:user_id, BIGINT, index: true, data_key: ["user", "id"], optional: true),
|
|
51
|
+
Webhookdb::Replicator::Column.new(
|
|
52
|
+
:merged_by_id,
|
|
53
|
+
BIGINT,
|
|
54
|
+
index: true,
|
|
55
|
+
data_key: ["merged_by", "id"],
|
|
56
|
+
optional: true,
|
|
57
|
+
),
|
|
58
|
+
Webhookdb::Replicator::Column.new(
|
|
59
|
+
:assignee_ids,
|
|
60
|
+
BIGINT_ARRAY,
|
|
61
|
+
index: true,
|
|
62
|
+
data_key: "assignees",
|
|
63
|
+
optional: true,
|
|
64
|
+
converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
|
|
65
|
+
),
|
|
66
|
+
Webhookdb::Replicator::Column.new(
|
|
67
|
+
:milestone_number,
|
|
68
|
+
INTEGER,
|
|
69
|
+
data_key: ["milestone", "number"],
|
|
70
|
+
optional: true,
|
|
71
|
+
),
|
|
72
|
+
Webhookdb::Replicator::Column.new(
|
|
73
|
+
:label_ids,
|
|
74
|
+
BIGINT_ARRAY,
|
|
75
|
+
data_key: "labels",
|
|
76
|
+
optional: true,
|
|
77
|
+
converter: Webhookdb::Replicator::Column.converter_array_pluck("id", BIGINT),
|
|
78
|
+
),
|
|
79
|
+
Webhookdb::Replicator::Column.new(:node_id, TEXT, index: true),
|
|
80
|
+
]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def _timestamp_column_name = :updated_at
|
|
84
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/github"
|
|
4
|
+
require "webhookdb/replicator/github_repo_v1_mixin"
|
|
5
|
+
|
|
6
|
+
class Webhookdb::Replicator::GithubReleaseV1 < Webhookdb::Replicator::Base
|
|
7
|
+
include Appydays::Loggable
|
|
8
|
+
include Webhookdb::Replicator::GithubRepoV1Mixin
|
|
9
|
+
|
|
10
|
+
def _mixin_backfill_url = "/releases"
|
|
11
|
+
def _mixin_webhook_events = ["Releases"]
|
|
12
|
+
def _mixin_webhook_key = "release"
|
|
13
|
+
def _mixin_fine_grained_permission = "Contents"
|
|
14
|
+
def _mixin_query_params(*) = {}
|
|
15
|
+
|
|
16
|
+
# @return [Webhookdb::Replicator::Descriptor]
|
|
17
|
+
def self.descriptor
|
|
18
|
+
return Webhookdb::Replicator::Descriptor.new(
|
|
19
|
+
name: "github_release_v1",
|
|
20
|
+
ctor: ->(sint) { Webhookdb::Replicator::GithubReleaseV1.new(sint) },
|
|
21
|
+
feature_roles: [],
|
|
22
|
+
resource_name_singular: "GitHub Release",
|
|
23
|
+
supports_webhooks: true,
|
|
24
|
+
supports_backfill: true,
|
|
25
|
+
api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/releases/releases"),
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def _remote_key_column
|
|
30
|
+
return Webhookdb::Replicator::Column.new(:github_id, BIGINT, data_key: "id")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def _denormalized_columns
|
|
34
|
+
return [
|
|
35
|
+
Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
|
|
36
|
+
Webhookdb::Replicator::Column.new(:published_at, TIMESTAMP, index: true),
|
|
37
|
+
Webhookdb::Replicator::Column.new(:row_updated_at, TIMESTAMP, defaulter: :now, optional: true, index: true),
|
|
38
|
+
Webhookdb::Replicator::Column.new(:node_id, TEXT, index: true),
|
|
39
|
+
Webhookdb::Replicator::Column.new(:tag_name, TEXT, index: true),
|
|
40
|
+
Webhookdb::Replicator::Column.new(
|
|
41
|
+
:author_id, BIGINT, index: true, data_key: ["author", "id"], optional: true,
|
|
42
|
+
),
|
|
43
|
+
]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def _timestamp_column_name = :row_updated_at
|
|
47
|
+
end
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/github"
|
|
4
|
+
|
|
5
|
+
# Mixin for repo-specific resources like issues and pull requests.
|
|
6
|
+
module Webhookdb::Replicator::GithubRepoV1Mixin
|
|
7
|
+
API_VERSION = "2022-11-28"
|
|
8
|
+
|
|
9
|
+
def self._api_docs_url(tail)
|
|
10
|
+
return "https://docs.github.com/en/rest#{tail}?apiVersion=#{API_VERSION}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @!attribute service_integration
|
|
14
|
+
# @return [Webhookdb::ServiceIntegration]
|
|
15
|
+
|
|
16
|
+
def _mixin_backfill_url = raise NotImplementedError("/issues, /pulls, etc")
|
|
17
|
+
def _mixin_webhook_events = raise NotImplementedError("Issues, Pulls, Issue comments, etc")
|
|
18
|
+
# https://docs.github.com/en/webhooks/webhook-events-and-payloads?actionType=demilestoned#issues
|
|
19
|
+
def _mixin_webhook_key = raise NotImplementedError("issue, etc")
|
|
20
|
+
# https://github.com/settings/personal-access-tokens/new
|
|
21
|
+
def _mixin_fine_grained_permission = raise NotImplementedError("Issues", etc)
|
|
22
|
+
# Query params to use in the list call. Should include sorting when available.
|
|
23
|
+
def _mixin_query_params(last_backfilled:) = raise NotImplementedError
|
|
24
|
+
# Some resources, like issues and pull requests, have a 'simple' representation
|
|
25
|
+
# in the list, and a full representation when fetched individually.
|
|
26
|
+
# Return the field that can be used to determine if the full resource needs to be fetched.
|
|
27
|
+
def _mixin_fetch_resource_if_field_missing = nil
|
|
28
|
+
|
|
29
|
+
def _fullreponame = self.service_integration.api_url
|
|
30
|
+
def _repoowner = self._fullreponame.split("/").first
|
|
31
|
+
def _reponame = self._fullreponame.split("/").last
|
|
32
|
+
def _valid_repo_name?(s) = %r{^[\w\-.]+/[\w\-.]+$} =~ s
|
|
33
|
+
|
|
34
|
+
# Extract the resource from the request.
|
|
35
|
+
# The resource can be a normal resource, or a webhook,
|
|
36
|
+
# with X-GitHub-Hook-ID key as per https://docs.github.com/en/webhooks/webhook-events-and-payloads
|
|
37
|
+
# The headers are the only things that identify a webhook payload consistently.
|
|
38
|
+
#
|
|
39
|
+
# Note that webhooks to a given integration can be for events we do not expect,
|
|
40
|
+
# such as someone sending events we aren't handling (ie, if they don't uncheck Pushes,
|
|
41
|
+
# we may get push events sent to the github_issue_v1 integration),
|
|
42
|
+
# and also for automated events like 'ping'.
|
|
43
|
+
def _resource_and_event(request)
|
|
44
|
+
# Note the canonical casing on the header name. GitHub sends X-GitHub-Hook-ID
|
|
45
|
+
# but it's normalized here.
|
|
46
|
+
is_webhook = (request.headers || {})["X-Github-Hook-Id"]
|
|
47
|
+
return request.body, nil unless is_webhook
|
|
48
|
+
resource = request.body.fetch(self._mixin_webhook_key, nil)
|
|
49
|
+
return nil, nil if resource.nil?
|
|
50
|
+
return resource, request.body
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def _update_where_expr
|
|
54
|
+
ts = self._timestamp_column_name
|
|
55
|
+
return self.qualified_table_sequel_identifier[ts] < Sequel[:excluded][ts]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def _webhook_response(request)
|
|
59
|
+
hash = request.env["HTTP_X_HUB_SIGNATURE_256"]
|
|
60
|
+
return Webhookdb::WebhookResponse.error("missing sha256") if hash.nil?
|
|
61
|
+
secret = self.service_integration.webhook_secret
|
|
62
|
+
return Webhookdb::WebhookResponse.error("no secret set, run `webhookdb integration setup`", status: 409) if
|
|
63
|
+
secret.nil?
|
|
64
|
+
request.body.rewind
|
|
65
|
+
request_data = request.body.read
|
|
66
|
+
verified = Webhookdb::Github.verify_webhook(request_data, hash, secret)
|
|
67
|
+
return Webhookdb::WebhookResponse.ok if verified
|
|
68
|
+
return Webhookdb::WebhookResponse.error("invalid sha256")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def _webhook_state_change_fields = super + ["repo_name"]
|
|
72
|
+
|
|
73
|
+
def process_state_change(field, value)
|
|
74
|
+
attr = field == "repo_name" ? "api_url" : field
|
|
75
|
+
return super(field, value, attr:)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def calculate_webhook_state_machine
|
|
79
|
+
step = Webhookdb::Replicator::StateMachineStep.new
|
|
80
|
+
return step if self._handle_repo_name_state_machine(step, "repo_name")
|
|
81
|
+
if self.service_integration.webhook_secret.blank?
|
|
82
|
+
step.output = %(Now, head to this route to create a webhook:
|
|
83
|
+
|
|
84
|
+
https://github.com/#{self.service_integration.api_url}/settings/hooks/new
|
|
85
|
+
|
|
86
|
+
For 'Payload URL', use this endpoint that is now available:
|
|
87
|
+
|
|
88
|
+
#{self._webhook_endpoint}
|
|
89
|
+
|
|
90
|
+
For 'Content type', choose 'application/json'. Form encoding works but loses some detail in events.
|
|
91
|
+
|
|
92
|
+
For 'Secret', choose your own secure secret, or use this one: '#{Webhookdb::Id.rand_enc(16)}'
|
|
93
|
+
|
|
94
|
+
For 'Which events would you like to trigger this webhook',
|
|
95
|
+
choose 'Let me select individual events',
|
|
96
|
+
uncheck 'Pushes', and select the following:
|
|
97
|
+
|
|
98
|
+
#{self._mixin_webhook_events.join("\n ")}
|
|
99
|
+
|
|
100
|
+
Make sure 'Active' is checked, and press 'Add webhook'.)
|
|
101
|
+
return step.secret_prompt("Webhook Secret").webhook_secret(self.service_integration)
|
|
102
|
+
end
|
|
103
|
+
step.output = %(Great! WebhookDB is now listening for #{self.resource_name_singular} webhooks.
|
|
104
|
+
#{self._query_help_output})
|
|
105
|
+
return step.completed
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# If api_url isn't set, prompt for it (via repo_name or api_url field).
|
|
109
|
+
def _handle_repo_name_state_machine(step, tfield)
|
|
110
|
+
if self.service_integration.api_url.blank?
|
|
111
|
+
step.output = %(You are about to start replicating #{self.resource_name_plural} for a repository into WebhookDB.
|
|
112
|
+
|
|
113
|
+
First we need the full repository name, like 'webhookdb/webhookdb-cli'.)
|
|
114
|
+
step.set_prompt("Repository name:").transition_field(self.service_integration, tfield)
|
|
115
|
+
return true
|
|
116
|
+
end
|
|
117
|
+
return false if self._valid_repo_name?(self.service_integration.api_url)
|
|
118
|
+
step.output = %(That repository is not valid. Include both the owner and name, like 'webhookdb/webhookdb-cli'.)
|
|
119
|
+
step.set_prompt("Repository name:").transition_field(self.service_integration, tfield)
|
|
120
|
+
return true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# If we can make an unauthed request and find the repo, it is public.
|
|
124
|
+
def _is_repo_public?
|
|
125
|
+
resp = Webhookdb::Http.post(
|
|
126
|
+
"https://github.com/#{self.service_integration.api_url}",
|
|
127
|
+
method: :head,
|
|
128
|
+
check: false,
|
|
129
|
+
timeout: 5,
|
|
130
|
+
logger: nil,
|
|
131
|
+
)
|
|
132
|
+
return resp.code == 200
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def calculate_backfill_state_machine
|
|
136
|
+
step = Webhookdb::Replicator::StateMachineStep.new
|
|
137
|
+
return step if self._handle_repo_name_state_machine(step, "api_url")
|
|
138
|
+
unless self.service_integration.backfill_secret.present?
|
|
139
|
+
repo_public = self._is_repo_public?
|
|
140
|
+
step.output = %(In order to backfill #{self.resource_name_plural},
|
|
141
|
+
WebhookDB requires an access token to authenticate.
|
|
142
|
+
|
|
143
|
+
You should go to https://github.com/settings/personal-access-tokens/new and create a new Personal Access Token.
|
|
144
|
+
|
|
145
|
+
For 'Expiration', give a custom date far in the future.
|
|
146
|
+
|
|
147
|
+
For 'Resource owner', choose the '#{self._repoowner}' organization.
|
|
148
|
+
**If it does not appear**, Fine-grained tokens are not enabled.
|
|
149
|
+
See instructions below.
|
|
150
|
+
|
|
151
|
+
For 'Repository access', choose 'Only select repositories', and the '#{self._fullreponame}' repository.
|
|
152
|
+
|
|
153
|
+
For 'Repository permissions', go to '#{self._mixin_fine_grained_permission}' and choose 'Read-only access'.
|
|
154
|
+
|
|
155
|
+
If you didn't see the needed owner under 'Resource owner,' it's because fine-grained tokens are not enabled.
|
|
156
|
+
Instead, create a new Classic personal access token from https://github.com/settings/tokens/new.
|
|
157
|
+
In the 'Note', mention this token is for WebhookDB,
|
|
158
|
+
give it an expiration, and under 'Scopes', ensure #{repo_public ? 'repo->public_repo' : 'repo'} is checked,
|
|
159
|
+
since #{self._fullreponame} is #{repo_public ? 'public' : 'private'}.
|
|
160
|
+
|
|
161
|
+
Then click 'Generate token'.)
|
|
162
|
+
return step.secret_prompt("Personal access token").backfill_secret(self.service_integration)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
unless (result = self.verify_backfill_credentials).verified
|
|
166
|
+
self.service_integration.replicator.clear_backfill_information
|
|
167
|
+
step.output = result.message
|
|
168
|
+
return step.secret_prompt("Personal access token").backfill_secret(self.service_integration)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
step.output = %(Great! We are going to start backfilling your #{self.resource_name_plural}.
|
|
172
|
+
#{self._query_help_output})
|
|
173
|
+
return step.completed
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def _verify_backfill_err_msg
|
|
177
|
+
return "That access token didn't seem to work. Please look over the instructions and try again."
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
JSON_CONTENT_TYPE = "application/vnd.github+json"
|
|
181
|
+
|
|
182
|
+
def _fetch_backfill_page(pagination_token, last_backfilled:)
|
|
183
|
+
if pagination_token.present?
|
|
184
|
+
url = pagination_token
|
|
185
|
+
query = {}
|
|
186
|
+
else
|
|
187
|
+
url = "https://api.github.com/repos/#{self.service_integration.api_url}#{self._mixin_backfill_url}"
|
|
188
|
+
query = {per_page: 100}
|
|
189
|
+
query.merge!(self._mixin_query_params(last_backfilled:))
|
|
190
|
+
end
|
|
191
|
+
response, data = self._http_get(url, query)
|
|
192
|
+
next_link = nil
|
|
193
|
+
if response.headers.key?("link")
|
|
194
|
+
links = Webhookdb::Github.parse_link_header(response.headers["link"])
|
|
195
|
+
next_link = links[:next] if links.key?(:next)
|
|
196
|
+
end
|
|
197
|
+
return data, next_link
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def _http_get(url, query)
|
|
201
|
+
response = Webhookdb::Http.get(
|
|
202
|
+
url,
|
|
203
|
+
query,
|
|
204
|
+
headers: {
|
|
205
|
+
"Accept" => JSON_CONTENT_TYPE,
|
|
206
|
+
"Authorization" => "Bearer #{self.service_integration.backfill_secret}",
|
|
207
|
+
"X-GitHub-Api-Version" => API_VERSION,
|
|
208
|
+
},
|
|
209
|
+
logger: self.logger,
|
|
210
|
+
timeout: Webhookdb::Github.http_timeout,
|
|
211
|
+
)
|
|
212
|
+
# Handle the GH-specific vnd JSON or general application/json
|
|
213
|
+
parsed = response.parsed_response
|
|
214
|
+
(parsed = Oj.load(parsed)) if response.headers["Content-Type"] == JSON_CONTENT_TYPE
|
|
215
|
+
return response, parsed
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def _fetch_enrichment(resource, _event, _request)
|
|
219
|
+
# If we're not set up to backfill, we cannot make an API call.
|
|
220
|
+
return nil if self.service_integration.backfill_secret.nil?
|
|
221
|
+
# We should fetch the full resource if the replicator needs it,
|
|
222
|
+
# and the resource does not have the key we require.
|
|
223
|
+
sentinel_key = self._mixin_fetch_resource_if_field_missing
|
|
224
|
+
return nil if sentinel_key.nil? || resource.key?(sentinel_key)
|
|
225
|
+
resource_url = resource.fetch("url")
|
|
226
|
+
begin
|
|
227
|
+
_response, data = self._http_get(resource_url, {})
|
|
228
|
+
rescue Webhookdb::Http::Error => e
|
|
229
|
+
# If the HTTP call fails due to an auth issue (or a deleted item),
|
|
230
|
+
# we should still upsert what we have.
|
|
231
|
+
# Tokens expire or can be revoked, but we don't want the webhook to stop inserting.
|
|
232
|
+
ignore_error = [401, 403, 404].include?(e.response.code)
|
|
233
|
+
return nil if ignore_error
|
|
234
|
+
raise e
|
|
235
|
+
end
|
|
236
|
+
return data
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def _prepare_for_insert(resource, event, request, enrichment)
|
|
240
|
+
# if enrichment is not nil, it's the detailed resource.
|
|
241
|
+
# See _mixin_fetch_resource_if_field_missing
|
|
242
|
+
return super(enrichment || resource, event, request, nil)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def _resource_to_data(resource, _event, _request, enrichment)
|
|
246
|
+
# if enrichment is not nil, it's the detailed resource.
|
|
247
|
+
# See _mixin_fetch_resource_if_field_missing
|
|
248
|
+
return enrichment || resource
|
|
249
|
+
end
|
|
250
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/github"
|
|
4
|
+
require "webhookdb/replicator/github_repo_v1_mixin"
|
|
5
|
+
|
|
6
|
+
class Webhookdb::Replicator::GithubRepositoryEventV1 < Webhookdb::Replicator::Base
|
|
7
|
+
include Appydays::Loggable
|
|
8
|
+
include Webhookdb::Replicator::GithubRepoV1Mixin
|
|
9
|
+
|
|
10
|
+
def _mixin_backfill_url = "/events"
|
|
11
|
+
def _mixin_fine_grained_permission = "Contents"
|
|
12
|
+
def _mixin_query_params(*) = {}
|
|
13
|
+
|
|
14
|
+
# @return [Webhookdb::Replicator::Descriptor]
|
|
15
|
+
def self.descriptor
|
|
16
|
+
return Webhookdb::Replicator::Descriptor.new(
|
|
17
|
+
name: "github_repository_event_v1",
|
|
18
|
+
ctor: ->(sint) { Webhookdb::Replicator::GithubRepositoryEventV1.new(sint) },
|
|
19
|
+
feature_roles: [],
|
|
20
|
+
resource_name_singular: "GitHub Repository Activity Event",
|
|
21
|
+
supports_webhooks: false,
|
|
22
|
+
supports_backfill: true,
|
|
23
|
+
api_docs_url: Webhookdb::Replicator::GithubRepoV1Mixin._api_docs_url("/activity/events"),
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def calculate_webhook_state_machine = raise NotImplementedError
|
|
28
|
+
|
|
29
|
+
def _remote_key_column
|
|
30
|
+
return Webhookdb::Replicator::Column.new(:github_id, TEXT, data_key: "id")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def _denormalized_columns
|
|
34
|
+
return [
|
|
35
|
+
Webhookdb::Replicator::Column.new(:type, TEXT, index: true),
|
|
36
|
+
Webhookdb::Replicator::Column.new(:created_at, TIMESTAMP, index: true),
|
|
37
|
+
Webhookdb::Replicator::Column.new(:row_updated_at, TIMESTAMP, defaulter: :now, optional: true, index: true),
|
|
38
|
+
Webhookdb::Replicator::Column.new(
|
|
39
|
+
:actor_id, BIGINT, index: true, data_key: ["actor", "id"], optional: true,
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def _timestamp_column_name = :row_updated_at
|
|
45
|
+
end
|