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,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
|
|
5
|
+
require "webhookdb/admin_api"
|
|
6
|
+
|
|
7
|
+
class Webhookdb::AdminAPI::DatabaseDocuments < Webhookdb::AdminAPI::V1
|
|
8
|
+
resource :database_documents do
|
|
9
|
+
route_param :id, type: Integer do
|
|
10
|
+
auth(:skip)
|
|
11
|
+
get :view do
|
|
12
|
+
(doc = Webhookdb::DatabaseDocument[params[:id]]) or forbidden!
|
|
13
|
+
doc.check_url(request.url) or forbidden!
|
|
14
|
+
content_type doc.content_type
|
|
15
|
+
env["api.format"] = :binary
|
|
16
|
+
body doc.content
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape_entity"
|
|
4
|
+
|
|
5
|
+
require "webhookdb/service/entities"
|
|
6
|
+
require "webhookdb/admin_api" unless defined? Webhookdb::AdminAPI
|
|
7
|
+
|
|
8
|
+
module Webhookdb::AdminAPI
|
|
9
|
+
CurrentCustomerEntity = Webhookdb::Service::Entities::CurrentCustomer
|
|
10
|
+
MoneyEntity = Webhookdb::Service::Entities::Money
|
|
11
|
+
TimeRangeEntity = Webhookdb::Service::Entities::TimeRange
|
|
12
|
+
|
|
13
|
+
class BaseEntity < Webhookdb::Service::Entities::Base; end
|
|
14
|
+
|
|
15
|
+
class RoleEntity < BaseEntity
|
|
16
|
+
expose :id
|
|
17
|
+
expose :name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class CustomerEntity < BaseEntity
|
|
21
|
+
expose :id
|
|
22
|
+
expose :created_at
|
|
23
|
+
expose :email
|
|
24
|
+
expose :name
|
|
25
|
+
expose :note
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class CustomerResetCodes < BaseEntity
|
|
29
|
+
expose :id
|
|
30
|
+
expose :created_at
|
|
31
|
+
expose :transport
|
|
32
|
+
expose :token
|
|
33
|
+
expose :used
|
|
34
|
+
expose :expire_at
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class DetailedCustomerEntity < CustomerEntity
|
|
38
|
+
expose :roles do |instance|
|
|
39
|
+
instance.roles.map(&:name)
|
|
40
|
+
end
|
|
41
|
+
expose :reset_codes, with: CustomerResetCodes
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class MessageBodyEntity < BaseEntity
|
|
45
|
+
expose :id
|
|
46
|
+
expose :content
|
|
47
|
+
expose :mediatype
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
class MessageDeliveryEntity < BaseEntity
|
|
51
|
+
expose :id
|
|
52
|
+
expose :created_at
|
|
53
|
+
expose :updated_at
|
|
54
|
+
expose :soft_deleted_at
|
|
55
|
+
expose :template
|
|
56
|
+
expose :transport_type
|
|
57
|
+
expose :transport_service
|
|
58
|
+
expose :transport_message_id
|
|
59
|
+
expose :sent_at
|
|
60
|
+
expose :to
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class MessageDeliveryWithBodiesEntity < MessageDeliveryEntity
|
|
64
|
+
expose :bodies, with: MessageBodyEntity
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
|
|
5
|
+
require "webhookdb/admin_api"
|
|
6
|
+
|
|
7
|
+
class Webhookdb::AdminAPI::MessageDeliveries < Webhookdb::AdminAPI::V1
|
|
8
|
+
helpers do
|
|
9
|
+
def lookup_delivery(params)
|
|
10
|
+
(batch = Webhookdb::Message::Delivery[params[:id]]) or not_found!
|
|
11
|
+
return batch
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
resource :message_deliveries do
|
|
16
|
+
desc "Return all message deliveries, newest first"
|
|
17
|
+
params do
|
|
18
|
+
use :pagination
|
|
19
|
+
use :ordering, model: Webhookdb::Message::Delivery
|
|
20
|
+
use :searchable
|
|
21
|
+
end
|
|
22
|
+
get do
|
|
23
|
+
ds = Webhookdb::Message::Delivery.dataset
|
|
24
|
+
if (to_like = search_param_to_sql(params, :to))
|
|
25
|
+
criteria = to_like | search_param_to_sql(params, :template)
|
|
26
|
+
ds = ds.where(criteria)
|
|
27
|
+
end
|
|
28
|
+
ds = order(ds, params)
|
|
29
|
+
ds = paginate(ds, params)
|
|
30
|
+
present_collection ds, with: Webhookdb::AdminAPI::MessageDeliveryEntity
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc "Return the delivery with the last ID"
|
|
34
|
+
get :last do
|
|
35
|
+
delivery = Webhookdb::Message::Delivery.last
|
|
36
|
+
present delivery, with: Webhookdb::AdminAPI::MessageDeliveryWithBodiesEntity
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
route_param :id, type: Integer do
|
|
40
|
+
desc "Return the delivery"
|
|
41
|
+
get do
|
|
42
|
+
delivery = lookup_delivery(params)
|
|
43
|
+
present delivery, with: Webhookdb::AdminAPI::MessageDeliveryWithBodiesEntity
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
resource :customers do
|
|
49
|
+
route_param :id, type: Integer do
|
|
50
|
+
resource :message_deliveries do
|
|
51
|
+
desc "Return all message deliveries for customer the given customers, as recipients or to their emails"
|
|
52
|
+
get do
|
|
53
|
+
# rubocop:disable Layout/LineLength
|
|
54
|
+
ds = Webhookdb::Message::Delivery.to_customers(Webhookdb::Customer.where(id: params[:id])).order(Sequel.desc(:id))
|
|
55
|
+
# rubocop:enable Layout/LineLength
|
|
56
|
+
present_collection ds, with: Webhookdb::AdminAPI::MessageDeliveryEntity
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
|
|
5
|
+
require "webhookdb/admin_api"
|
|
6
|
+
|
|
7
|
+
class Webhookdb::AdminAPI::Roles < Webhookdb::AdminAPI::V1
|
|
8
|
+
resource :roles do
|
|
9
|
+
desc "Return all roles, ordered by name"
|
|
10
|
+
get do
|
|
11
|
+
ds = Webhookdb::Role.dataset.order(:name)
|
|
12
|
+
present_collection ds, with: Webhookdb::AdminAPI::RoleEntity
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
|
|
5
|
+
require "webhookdb"
|
|
6
|
+
require "webhookdb/service"
|
|
7
|
+
|
|
8
|
+
# API is the namespace module for Admin API resources.
|
|
9
|
+
module Webhookdb::AdminAPI
|
|
10
|
+
require "webhookdb/admin_api/entities"
|
|
11
|
+
|
|
12
|
+
class V1 < Webhookdb::Service
|
|
13
|
+
def self.inherited(subclass)
|
|
14
|
+
super
|
|
15
|
+
subclass.instance_eval do
|
|
16
|
+
version "v1", using: :path
|
|
17
|
+
format :json
|
|
18
|
+
|
|
19
|
+
content_type :csv, "text/csv"
|
|
20
|
+
|
|
21
|
+
require "webhookdb/service/helpers"
|
|
22
|
+
helpers Webhookdb::Service::Helpers
|
|
23
|
+
|
|
24
|
+
auth(:admin)
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
Sentry.configure_scope do |scope|
|
|
28
|
+
scope.set_tags(application: "admin-api")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb" unless defined?(Webhookdb)
|
|
4
|
+
|
|
5
|
+
# Value returned or raised from a method that deals with aggregate success or failure.
|
|
6
|
+
#
|
|
7
|
+
# Sometimes we want to process a collection of items,
|
|
8
|
+
# and not fail the entire thing if some fail. In this case, we can return an AggregateResult.
|
|
9
|
+
# If the AggregateResult is returned, we know all items processed.
|
|
10
|
+
# If it is raised, at least some of the items errored.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
# ag = AggregateResult.new
|
|
14
|
+
# items.each do |item|
|
|
15
|
+
# ag.success(myfunc(item))
|
|
16
|
+
# rescue => e
|
|
17
|
+
# ag.failure(item, e)
|
|
18
|
+
# end
|
|
19
|
+
# return ag.finish
|
|
20
|
+
#
|
|
21
|
+
class Webhookdb::AggregateResult < StandardError
|
|
22
|
+
attr_reader :successes, :failures, :errors
|
|
23
|
+
|
|
24
|
+
def initialize(existing=nil)
|
|
25
|
+
if existing.nil?
|
|
26
|
+
@successes = []
|
|
27
|
+
@failures = []
|
|
28
|
+
@errors = []
|
|
29
|
+
super("awaiting result")
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
# We can only set the exception message from initialization
|
|
33
|
+
@successes = existing.successes
|
|
34
|
+
@failures = existing.failures
|
|
35
|
+
@errors = existing.errors
|
|
36
|
+
if @failures.empty?
|
|
37
|
+
super("No errors")
|
|
38
|
+
return
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
lines = ["Multiple errors occurred:"]
|
|
42
|
+
@failures.each_with_index do |f, i|
|
|
43
|
+
lines << " #{f.inspect}: #{@errors[i].message}"
|
|
44
|
+
end
|
|
45
|
+
super(lines.join("\n"))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def success(i)
|
|
49
|
+
@successes << i
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def failure(i, e)
|
|
53
|
+
@failures << i
|
|
54
|
+
@errors << e
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def finish
|
|
58
|
+
raise InvalidPrecondition, "failures.length must equal errors.length" unless @failures.length == @errors.length
|
|
59
|
+
result = Webhookdb::AggregateResult.new(self)
|
|
60
|
+
return result if self.failures.empty?
|
|
61
|
+
raise result
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/api"
|
|
4
|
+
require "webhookdb/demo_mode"
|
|
5
|
+
|
|
6
|
+
class Webhookdb::API::Auth < Webhookdb::API::V1
|
|
7
|
+
include Webhookdb::Service::Types
|
|
8
|
+
|
|
9
|
+
resource :auth do
|
|
10
|
+
helpers do
|
|
11
|
+
def guard_logged_in!
|
|
12
|
+
c = current_customer?
|
|
13
|
+
return if c.nil?
|
|
14
|
+
merror!(403, "You are already logged in as #{c.email}. You must log out first.", code: "already_logged_in")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
helpers do
|
|
19
|
+
def finish_auth(me)
|
|
20
|
+
set_customer(me) if me
|
|
21
|
+
extras = {}
|
|
22
|
+
extras[:current_customer] = Webhookdb::API::CurrentCustomerEntity.represent(me).as_json if me
|
|
23
|
+
return extras
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
params do
|
|
28
|
+
optional :email,
|
|
29
|
+
type: String,
|
|
30
|
+
coerce_with: NormalizedEmail,
|
|
31
|
+
prompt: {
|
|
32
|
+
message: "Welcome to WebhookDB!\nPlease enter your email:",
|
|
33
|
+
demo_mode_proc: ->(r) { r.params[:email] = "demo@webhookdb.com" },
|
|
34
|
+
}
|
|
35
|
+
optional :token, type: String
|
|
36
|
+
end
|
|
37
|
+
post do
|
|
38
|
+
message = ""
|
|
39
|
+
if Webhookdb::DemoMode.client_enabled?
|
|
40
|
+
membership, step, message = Webhookdb::DemoMode.handle_auth
|
|
41
|
+
me = membership.customer
|
|
42
|
+
extras = finish_auth(me)
|
|
43
|
+
status 200
|
|
44
|
+
elsif params[:token].blank?
|
|
45
|
+
guard_logged_in!
|
|
46
|
+
begin
|
|
47
|
+
step, _ = Webhookdb::Customer.register_or_login(email: params[:email])
|
|
48
|
+
rescue Webhookdb::Customer::SignupDisabled
|
|
49
|
+
merror!(402, "Sorry, new signups are currently disabled.", code: "signup_disabled")
|
|
50
|
+
end
|
|
51
|
+
extras = {}
|
|
52
|
+
status 202
|
|
53
|
+
else
|
|
54
|
+
guard_logged_in!
|
|
55
|
+
step, me = Webhookdb::Customer.finish_otp(
|
|
56
|
+
Webhookdb::Customer[email: params[:email]], token: params[:token],
|
|
57
|
+
)
|
|
58
|
+
extras = finish_auth(me)
|
|
59
|
+
status 200
|
|
60
|
+
end
|
|
61
|
+
present step, with: Webhookdb::API::StateMachineEntity, extras:, message:
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
resource :login_otp do
|
|
65
|
+
route_param :opaque_id do
|
|
66
|
+
desc "Verify the OTP and auth the customer"
|
|
67
|
+
params do
|
|
68
|
+
requires :value
|
|
69
|
+
end
|
|
70
|
+
post do
|
|
71
|
+
guard_logged_in!
|
|
72
|
+
step, me = Webhookdb::Customer.finish_otp(
|
|
73
|
+
Webhookdb::Customer[opaque_id: params[:opaque_id]], token: params[:value],
|
|
74
|
+
)
|
|
75
|
+
extras = finish_auth(me)
|
|
76
|
+
status 200
|
|
77
|
+
present step, with: Webhookdb::API::StateMachineEntity, extras:
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
post :logout do
|
|
83
|
+
delete_session_cookies
|
|
84
|
+
status 200
|
|
85
|
+
present({}, with: Webhookdb::API::BaseEntity, message: "You have logged out.")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
params do
|
|
89
|
+
requires :form_name, type: String
|
|
90
|
+
optional :email, type: String
|
|
91
|
+
optional :name, type: String
|
|
92
|
+
optional :message, type: String
|
|
93
|
+
end
|
|
94
|
+
post :contact do
|
|
95
|
+
fields = []
|
|
96
|
+
fields << {title: "Form", value: params[:form_name], short: true}
|
|
97
|
+
fields << {title: "IP", value: request.ip, short: true}
|
|
98
|
+
fields << {title: "User Agent", value: request.user_agent || "", short: false}
|
|
99
|
+
if (email = params[:email])
|
|
100
|
+
fields << {title: "Email", value: email, short: true}
|
|
101
|
+
end
|
|
102
|
+
if (name = params[:name])
|
|
103
|
+
fields << {title: "Name", value: name, short: true}
|
|
104
|
+
end
|
|
105
|
+
if (msg = params[:message])
|
|
106
|
+
fields << {title: "Message", value: msg, short: false}
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
Webhookdb::DeveloperAlert.new(
|
|
110
|
+
subsystem: "New Contact",
|
|
111
|
+
emoji: ":mailbox_with_mail:",
|
|
112
|
+
fallback: fields.
|
|
113
|
+
map { |f| "#{f[:title]}: #{f[:value]}" }.
|
|
114
|
+
join(", "),
|
|
115
|
+
fields:,
|
|
116
|
+
).emit
|
|
117
|
+
|
|
118
|
+
status 200
|
|
119
|
+
present({message: "ok"})
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
|
|
5
|
+
# Some routes allow the SHA256 hash hexdigest connection string
|
|
6
|
+
# to be used in place of normal authentication (for example, queries to the database,
|
|
7
|
+
# which are not tied to a user). Do NOT extract this automatically (like org_identifier)
|
|
8
|
+
# since we want endpoints to specify that they use the param explicitly.
|
|
9
|
+
module Webhookdb::API::ConnstrAuth
|
|
10
|
+
ALGOS = ["Sha256"].freeze
|
|
11
|
+
|
|
12
|
+
def self.headers_desc
|
|
13
|
+
return ALGOS.to_h do |algo|
|
|
14
|
+
h = {
|
|
15
|
+
required: false,
|
|
16
|
+
algo:,
|
|
17
|
+
description: "Hex digest of the #{algo} hash of the organization connection string, " \
|
|
18
|
+
"like Ruby's Digest::#{algo.upcase}.hexdigest(conn_str). " \
|
|
19
|
+
"Can be used in place of normal auth.",
|
|
20
|
+
}
|
|
21
|
+
["Whdb-#{algo}-Conn", h]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.find_authed(orgs, request)
|
|
26
|
+
orgs.find do |o|
|
|
27
|
+
self.headers_desc.each do |header_name, desc|
|
|
28
|
+
header_value = request.headers[header_name]
|
|
29
|
+
next if header_value.blank?
|
|
30
|
+
org_value = Digest.const_get(desc.fetch(:algo).upcase.to_sym).send(:hexdigest, o.readonly_connection_url)
|
|
31
|
+
return o if header_value == org_value
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
return nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "grape"
|
|
4
|
+
|
|
5
|
+
require "webhookdb/api"
|
|
6
|
+
require "webhookdb/replicator"
|
|
7
|
+
|
|
8
|
+
class Webhookdb::API::Db < Webhookdb::API::V1
|
|
9
|
+
helpers do
|
|
10
|
+
params :fdw do
|
|
11
|
+
optional :message_fdw, type: Boolean
|
|
12
|
+
optional :message_views, type: Boolean
|
|
13
|
+
optional :message_all, type: Boolean
|
|
14
|
+
requires :remote_server_name, type: String
|
|
15
|
+
requires :fetch_size, type: String
|
|
16
|
+
requires :local_schema, type: String
|
|
17
|
+
requires :view_schema, type: String
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def run_fdw
|
|
21
|
+
org = lookup_org!
|
|
22
|
+
resp = Webhookdb::Organization::DbBuilder.new(org).generate_fdw_payload(
|
|
23
|
+
remote_server_name: params[:remote_server_name],
|
|
24
|
+
fetch_size: params[:fetch_size],
|
|
25
|
+
local_schema: params[:local_schema],
|
|
26
|
+
view_schema: params[:view_schema],
|
|
27
|
+
)
|
|
28
|
+
resp[:message] = if params[:message_fdw]
|
|
29
|
+
resp[:fdw_sql]
|
|
30
|
+
elsif params[:message_views]
|
|
31
|
+
resp[:views_sql]
|
|
32
|
+
else
|
|
33
|
+
resp[:compound_sql]
|
|
34
|
+
end
|
|
35
|
+
status 200
|
|
36
|
+
present resp
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
resource :db do
|
|
41
|
+
route_param :org_identifier, type: String do
|
|
42
|
+
desc "Returns the connection string"
|
|
43
|
+
get :connection do
|
|
44
|
+
_customer = current_customer
|
|
45
|
+
org = lookup_org!
|
|
46
|
+
r = {connection_url: org.readonly_connection_url}
|
|
47
|
+
present r
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
desc "Returns a list of all tables in the organization's db."
|
|
51
|
+
get :tables do
|
|
52
|
+
_customer = current_customer
|
|
53
|
+
org = lookup_org!
|
|
54
|
+
tables = org.readonly_connection do |db|
|
|
55
|
+
db.tables(schema: org.replication_schema)
|
|
56
|
+
end
|
|
57
|
+
message = ""
|
|
58
|
+
if tables.empty?
|
|
59
|
+
message = "You have not set up any service integrations.\n" \
|
|
60
|
+
"Use `webhookdb services list` and `webhookdb integrations create` to get started."
|
|
61
|
+
end
|
|
62
|
+
present({tables:, message:})
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
desc "Enqueues a database migration."
|
|
66
|
+
params do
|
|
67
|
+
optional :admin_url, type: String, prompt: {
|
|
68
|
+
message: "ADMIN Postgres connection URL, in the form 'postgres://user:password@host:port/dbname',\n" \
|
|
69
|
+
"that is capable of administrative operations on your database,\n" \
|
|
70
|
+
"such as creating and dropping schemas and tables.\n" \
|
|
71
|
+
"Input ADMIN URL, then press Enter:",
|
|
72
|
+
secret: true,
|
|
73
|
+
disable: ->(_) { !Webhookdb::Organization::DbBuilder.allow_public_migrations },
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
optional :readonly_url, type: String, prompt: {
|
|
77
|
+
message: "READONLY Postgres connection URL.\n" \
|
|
78
|
+
"This string is displayed when you ask for your organization's connection information.\n" \
|
|
79
|
+
"If you are okay with this being your ADMIN URL, leave it blank.\n" \
|
|
80
|
+
"Input READONLY URL, or leave blank, then press Enter:",
|
|
81
|
+
secret: true,
|
|
82
|
+
optional: true,
|
|
83
|
+
disable: ->(_) { !Webhookdb::Organization::DbBuilder.allow_public_migrations },
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
post :migrate_database do
|
|
87
|
+
unless Webhookdb::Organization::DbBuilder.allow_public_migrations
|
|
88
|
+
merror!(403,
|
|
89
|
+
"Public database migrations are not enabled. Email #{Webhookdb.oss_repo_url} for more information.",
|
|
90
|
+
code: "migrations_disabled",
|
|
91
|
+
alert: true,)
|
|
92
|
+
end
|
|
93
|
+
ensure_admin!
|
|
94
|
+
org = lookup_org!
|
|
95
|
+
# if the readonly url is blank, default to the admin url
|
|
96
|
+
readonly_url = params[:readonly_url].blank? ? params[:admin_url] : params[:readonly_url]
|
|
97
|
+
dbm = Webhookdb::Organization::DatabaseMigration.enqueue(
|
|
98
|
+
admin_connection_url_raw: params[:admin_url],
|
|
99
|
+
readonly_connection_url_raw: readonly_url,
|
|
100
|
+
public_host: "",
|
|
101
|
+
started_by: current_customer,
|
|
102
|
+
organization: org,
|
|
103
|
+
)
|
|
104
|
+
message = "Your database migration has been enqueued. You'll recieve an email when it is complete."
|
|
105
|
+
status 200
|
|
106
|
+
present dbm, with: Webhookdb::API::DatabaseMigrationEntity, message:
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
desc "Gets list of database migrations for org."
|
|
110
|
+
get :migrations do
|
|
111
|
+
org = lookup_org!
|
|
112
|
+
dbms = org.database_migrations
|
|
113
|
+
message = ""
|
|
114
|
+
message = "Organization #{org.name} has no database migrations" if dbms.empty?
|
|
115
|
+
status 200
|
|
116
|
+
present_collection dbms, with: Webhookdb::API::DatabaseMigrationEntity, message:
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
desc "Execute an arbitrary query against an org's connection string" do
|
|
120
|
+
headers Webhookdb::API::ConnstrAuth.headers_desc
|
|
121
|
+
end
|
|
122
|
+
params do
|
|
123
|
+
optional :query, type: String, prompt: "Input your SQL query, and then press Enter:"
|
|
124
|
+
end
|
|
125
|
+
post :sql do
|
|
126
|
+
org = lookup_org!(allow_connstr_auth: true)
|
|
127
|
+
begin
|
|
128
|
+
r = org.execute_readonly_query(params[:query])
|
|
129
|
+
rescue Sequel::DatabaseError => e
|
|
130
|
+
self.logger.error("db_query_database_error", error: e)
|
|
131
|
+
# We want to handle InsufficientPrivileges and UndefinedTable explicitly
|
|
132
|
+
# since we can hint the user at what to do.
|
|
133
|
+
# Otherwise, we should just return the Postgres exception.
|
|
134
|
+
case e.wrapped_exception
|
|
135
|
+
when PG::UndefinedTable
|
|
136
|
+
missing_table = e.wrapped_exception.message.match(/relation (.+) does not/)&.captures&.first
|
|
137
|
+
msg = "The table #{missing_table} does not exist. Run `webhookdb db tables` to see available tables." if
|
|
138
|
+
missing_table
|
|
139
|
+
when PG::InsufficientPrivilege
|
|
140
|
+
msg = "You do not have permission to perform this query. Queries must be read-only."
|
|
141
|
+
else
|
|
142
|
+
msg = e.wrapped_exception.message
|
|
143
|
+
end
|
|
144
|
+
merror!(403, msg, code: "invalid_query")
|
|
145
|
+
end
|
|
146
|
+
status 200
|
|
147
|
+
present({rows: r.rows, headers: r.columns, max_rows_reached: r.max_rows_reached})
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
params do
|
|
151
|
+
optional :guard_confirm, prompt: {
|
|
152
|
+
message: "WARNING: This will invalidate your existing database credentials. " \
|
|
153
|
+
"Enter to proceed, or Ctrl+C to quit:",
|
|
154
|
+
confirm: true,
|
|
155
|
+
}
|
|
156
|
+
end
|
|
157
|
+
post :roll_credentials do
|
|
158
|
+
ensure_admin!
|
|
159
|
+
org = lookup_org!
|
|
160
|
+
org.roll_database_credentials
|
|
161
|
+
connection_url = org.readonly_connection_url
|
|
162
|
+
status 200
|
|
163
|
+
present(
|
|
164
|
+
{connection_url:},
|
|
165
|
+
with: Webhookdb::API::BaseEntity,
|
|
166
|
+
message: "Your database connection string is now: #{connection_url}",
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
params do
|
|
171
|
+
use :fdw
|
|
172
|
+
end
|
|
173
|
+
post :fdw do
|
|
174
|
+
run_fdw
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
resource :organizations do
|
|
180
|
+
route_param :org_identifier, type: String do
|
|
181
|
+
# See https://github.com/webhookdb/webhookdb/issues/286
|
|
182
|
+
desc "DEPRECATED: Use /v1/db/:key/fdw instead"
|
|
183
|
+
post :fdw do
|
|
184
|
+
run_fdw
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/api"
|
|
4
|
+
|
|
5
|
+
class Webhookdb::API::Demo < Webhookdb::API::V1
|
|
6
|
+
resource :demo do
|
|
7
|
+
post :data do
|
|
8
|
+
merror!(403, "Demo mode is not enabled") unless Webhookdb::DemoMode.server_enabled?
|
|
9
|
+
r = Webhookdb::DemoMode.build_demo_data
|
|
10
|
+
status 200
|
|
11
|
+
present(r)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|