webhookdb 1.2.2 → 1.3.1
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 +4 -4
- data/admin-dist/assets/index-6aebf805.js +264 -0
- data/admin-dist/favicon.ico +0 -0
- data/admin-dist/index.html +130 -0
- data/admin-dist/manifest.json +15 -0
- data/data/messages/replicators/url-recorder.liquid +20 -0
- data/data/messages/templates/errors/signalwire_send_sms.email.liquid +31 -0
- data/data/messages/web/install-customer-login.liquid +6 -5
- data/data/messages/web/install-error.liquid +1 -1
- data/data/messages/web/install-forbidden.liquid +25 -0
- data/data/messages/web/install-org-chooser.liquid +40 -0
- data/data/messages/web/install-success.liquid +2 -1
- data/data/messages/web/install.liquid +2 -1
- data/data/messages/web/partials/head.liquid +2 -0
- data/data/messages/web/styles.liquid +24 -0
- data/db/migrations/041_views.rb +20 -0
- data/db/migrations/042_sint_lock.rb +10 -0
- data/db/migrations/043_text_search.rb +28 -0
- data/db/migrations/044_oauth_session_token_cache.rb +21 -0
- data/integration/auth_spec.rb +2 -2
- data/lib/sequel/plugins/text_searchable.rb +165 -0
- data/lib/sequel/text_searchable.rb +42 -0
- data/lib/webhookdb/admin_api/auth.rb +24 -3
- data/lib/webhookdb/admin_api/data_provider.rb +196 -0
- data/lib/webhookdb/admin_api/entities.rb +143 -28
- data/lib/webhookdb/admin_api.rb +0 -2
- data/lib/webhookdb/api/auth.rb +5 -6
- data/lib/webhookdb/api/db.rb +31 -6
- data/lib/webhookdb/api/entities.rb +7 -1
- data/lib/webhookdb/api/helpers.rb +6 -25
- data/lib/webhookdb/api/install.rb +204 -79
- data/lib/webhookdb/api/organizations.rb +14 -12
- data/lib/webhookdb/api/saved_queries.rb +9 -3
- data/lib/webhookdb/api/saved_views.rb +99 -0
- data/lib/webhookdb/api/service_integrations.rb +15 -9
- data/lib/webhookdb/api/subscriptions.rb +3 -1
- data/lib/webhookdb/api/sync_targets.rb +9 -7
- data/lib/webhookdb/api/system.rb +1 -0
- data/lib/webhookdb/api/webhook_subscriptions.rb +3 -1
- data/lib/webhookdb/apps.rb +30 -7
- data/lib/webhookdb/async/audit_logger.rb +2 -0
- data/lib/webhookdb/async.rb +5 -0
- data/lib/webhookdb/backfill_job/service_integration_lock.rb +22 -0
- data/lib/webhookdb/backfill_job.rb +9 -0
- data/lib/webhookdb/customer.rb +5 -0
- data/lib/webhookdb/database_document.rb +1 -1
- data/lib/webhookdb/db_adapter/default_sql.rb +1 -1
- data/lib/webhookdb/db_adapter.rb +20 -4
- data/lib/webhookdb/fixtures/message_bodies.rb +34 -0
- data/lib/webhookdb/fixtures/organizations.rb +5 -0
- data/lib/webhookdb/fixtures/roles.rb +14 -0
- data/lib/webhookdb/fixtures/saved_views.rb +25 -0
- data/lib/webhookdb/fixtures/webhook_subscription_deliveries.rb +18 -0
- data/lib/webhookdb/http.rb +8 -2
- data/lib/webhookdb/icalendar.rb +3 -0
- data/lib/webhookdb/idempotency.rb +69 -22
- data/lib/webhookdb/increase.rb +69 -21
- data/lib/webhookdb/intercom.rb +10 -3
- data/lib/webhookdb/jobs/backfill.rb +3 -1
- data/lib/webhookdb/jobs/emailer.rb +0 -1
- data/lib/webhookdb/jobs/icalendar_delete_stale_cancelled_events.rb +19 -0
- data/lib/webhookdb/jobs/icalendar_enqueue_syncs.rb +1 -1
- data/lib/webhookdb/jobs/icalendar_sync.rb +1 -1
- data/lib/webhookdb/jobs/increase_event_handler.rb +20 -0
- data/lib/webhookdb/jobs/scheduled_backfills.rb +2 -1
- data/lib/webhookdb/jobs/sync_target_run_sync.rb +3 -1
- data/lib/webhookdb/message/body.rb +6 -4
- data/lib/webhookdb/message/delivery.rb +2 -0
- data/lib/webhookdb/messages/error_icalendar_fetch.rb +1 -2
- data/lib/webhookdb/messages/error_signalwire_send_sms.rb +48 -0
- data/lib/webhookdb/oauth/fake_provider.rb +44 -0
- data/lib/webhookdb/oauth/front_provider.rb +1 -2
- data/lib/webhookdb/oauth/increase_provider.rb +80 -0
- data/lib/webhookdb/oauth/intercom_provider.rb +3 -11
- data/lib/webhookdb/oauth/session.rb +20 -0
- data/lib/webhookdb/oauth.rb +7 -21
- data/lib/webhookdb/organization/alerting.rb +2 -0
- data/lib/webhookdb/organization/database_migration.rb +3 -0
- data/lib/webhookdb/organization.rb +37 -6
- data/lib/webhookdb/organization_membership.rb +14 -7
- data/lib/webhookdb/postgres.rb +2 -0
- data/lib/webhookdb/replicator/base.rb +1 -0
- data/lib/webhookdb/replicator/docgen.rb +9 -1
- data/lib/webhookdb/replicator/fake.rb +2 -3
- data/lib/webhookdb/replicator/front_signalwire_message_channel_app_v1.rb +49 -14
- data/lib/webhookdb/replicator/icalendar_calendar_v1.rb +97 -17
- data/lib/webhookdb/replicator/icalendar_event_v1.rb +104 -2
- data/lib/webhookdb/replicator/increase_account_number_v1.rb +6 -43
- data/lib/webhookdb/replicator/increase_account_transfer_v1.rb +7 -24
- data/lib/webhookdb/replicator/increase_account_v1.rb +7 -31
- data/lib/webhookdb/replicator/increase_ach_transfer_v1.rb +5 -43
- data/lib/webhookdb/replicator/increase_app_v1.rb +78 -0
- data/lib/webhookdb/replicator/increase_check_transfer_v1.rb +23 -29
- data/lib/webhookdb/replicator/increase_event_v1.rb +41 -0
- data/lib/webhookdb/replicator/increase_limit_v1.rb +9 -34
- data/lib/webhookdb/replicator/increase_transaction_v1.rb +5 -30
- data/lib/webhookdb/replicator/increase_v1_mixin.rb +58 -78
- data/lib/webhookdb/replicator/increase_wire_transfer_v1.rb +5 -24
- data/lib/webhookdb/replicator/intercom_contact_v1.rb +51 -4
- data/lib/webhookdb/replicator/intercom_conversation_v1.rb +42 -6
- data/lib/webhookdb/replicator/intercom_marketplace_root_v1.rb +2 -13
- data/lib/webhookdb/replicator/intercom_v1_mixin.rb +20 -16
- data/lib/webhookdb/replicator/oauth_refresh_access_token_mixin.rb +1 -1
- data/lib/webhookdb/replicator/sponsy_v1_mixin.rb +1 -1
- data/lib/webhookdb/replicator/transistor_episode_v1.rb +17 -0
- data/lib/webhookdb/replicator/url_recorder_v1.rb +137 -0
- data/lib/webhookdb/replicator/webhook_request.rb +4 -0
- data/lib/webhookdb/replicator.rb +8 -0
- data/lib/webhookdb/role.rb +5 -2
- data/lib/webhookdb/saved_query.rb +23 -0
- data/lib/webhookdb/saved_view.rb +73 -0
- data/lib/webhookdb/sentry.rb +2 -0
- data/lib/webhookdb/service/entities.rb +0 -4
- data/lib/webhookdb/service/helpers.rb +5 -0
- data/lib/webhookdb/service/middleware.rb +9 -0
- data/lib/webhookdb/service/types.rb +10 -8
- data/lib/webhookdb/service/validators.rb +1 -2
- data/lib/webhookdb/service/view_api.rb +1 -1
- data/lib/webhookdb/service_integration.rb +17 -15
- data/lib/webhookdb/spec_helpers/shared_examples_for_replicators.rb +8 -8
- data/lib/webhookdb/spec_helpers/whdb.rb +3 -2
- data/lib/webhookdb/subscription.rb +2 -0
- data/lib/webhookdb/sync_target.rb +10 -2
- data/lib/webhookdb/tasks/message.rb +3 -1
- data/lib/webhookdb/version.rb +1 -1
- data/lib/webhookdb/webhook_subscription/delivery.rb +2 -0
- data/lib/webhookdb/webhook_subscription.rb +2 -0
- metadata +57 -9
- data/lib/webhookdb/admin_api/customers.rb +0 -63
- data/lib/webhookdb/admin_api/message_deliveries.rb +0 -61
- data/lib/webhookdb/admin_api/roles.rb +0 -15
|
@@ -10,13 +10,15 @@ require "webhookdb/async/audit_logger"
|
|
|
10
10
|
require "webhookdb/jobs/process_webhook"
|
|
11
11
|
|
|
12
12
|
class Webhookdb::API::ServiceIntegrations < Webhookdb::API::V1
|
|
13
|
+
include Webhookdb::Service::Types
|
|
14
|
+
|
|
13
15
|
# These URLs are not used by the CLI-
|
|
14
16
|
# they are the url that customers should point their webhooks to.
|
|
15
17
|
# We can't check org permissions on this endpoint
|
|
16
18
|
# because external services (so no auth) will be posting webhooks here.
|
|
17
19
|
# Depend on webhook verification to ensure the request is valid.
|
|
18
20
|
resource :service_integrations do
|
|
19
|
-
route [:post, :put, :delete, :patch], "/:opaque_id*" do
|
|
21
|
+
route [:get, :post, :put, :delete, :patch], "/:opaque_id*" do
|
|
20
22
|
opaque_id = params[:opaque_id]
|
|
21
23
|
handle_webhook_request(opaque_id) do
|
|
22
24
|
Webhookdb::ServiceIntegration[opaque_id:] or merror!(400, "No integration with that id")
|
|
@@ -41,7 +43,7 @@ class Webhookdb::API::ServiceIntegrations < Webhookdb::API::V1
|
|
|
41
43
|
resource :create do
|
|
42
44
|
helpers do
|
|
43
45
|
def create_integration(org, name)
|
|
44
|
-
available_services_list = org.
|
|
46
|
+
available_services_list = org.available_replicators.map(&:name).sort.join("\n\t")
|
|
45
47
|
|
|
46
48
|
service_name_invalid = Webhookdb::Replicator.registered(name).nil?
|
|
47
49
|
if service_name_invalid
|
|
@@ -55,7 +57,7 @@ Run `webhookdb services list` to see available services, and try again with the
|
|
|
55
57
|
end
|
|
56
58
|
|
|
57
59
|
# If org does not have access to the given service
|
|
58
|
-
unless org.
|
|
60
|
+
unless org.available_replicators.map(&:name).include?(name)
|
|
59
61
|
step = Webhookdb::Replicator::StateMachineStep.new
|
|
60
62
|
step.needs_input = false
|
|
61
63
|
step.output =
|
|
@@ -95,13 +97,13 @@ If the list does not look correct, you can contact support at #{Webhookdb.suppor
|
|
|
95
97
|
:guard_confirm,
|
|
96
98
|
"WARNING: #{org.name} already has an integration for service #{params[:service_name]}.\n" \
|
|
97
99
|
"Press Enter to create another, or Ctrl+C to quit.\n" \
|
|
98
|
-
"Modify the existing integration using `webhookdb integrations #{existing.opaque_id}
|
|
100
|
+
"Modify the existing integration using `webhookdb integrations setup #{existing.opaque_id}`",
|
|
99
101
|
)
|
|
100
102
|
end
|
|
101
103
|
end
|
|
102
104
|
desc "Create service integration on a given organization"
|
|
103
105
|
params do
|
|
104
|
-
optional :service_name, type:
|
|
106
|
+
optional :service_name, type: TrimmedString,
|
|
105
107
|
prompt: "Enter the name of the service to create an integration for.\n" \
|
|
106
108
|
"Run 'webhookdb services list' to see available services:"
|
|
107
109
|
optional :guard_confirm
|
|
@@ -187,7 +189,9 @@ If the list does not look correct, you can contact support at #{Webhookdb.suppor
|
|
|
187
189
|
|
|
188
190
|
desc "Returns information about the integration."
|
|
189
191
|
params do
|
|
190
|
-
optional :field,
|
|
192
|
+
optional :field,
|
|
193
|
+
type: TrimmedString,
|
|
194
|
+
values: TrimmedString.map(Webhookdb::ServiceIntegration::INTEGRATION_INFO_FIELDS.keys + [""])
|
|
191
195
|
end
|
|
192
196
|
post :info do
|
|
193
197
|
ensure_plan_supports!
|
|
@@ -339,7 +343,7 @@ If the list does not look correct, you can contact support at #{Webhookdb.suppor
|
|
|
339
343
|
end
|
|
340
344
|
|
|
341
345
|
params do
|
|
342
|
-
optional :confirm, type:
|
|
346
|
+
optional :confirm, type: TrimmedString
|
|
343
347
|
end
|
|
344
348
|
post :delete do
|
|
345
349
|
ensure_plan_supports!
|
|
@@ -384,9 +388,11 @@ The tables and all data for this integration and its dependents will also be rem
|
|
|
384
388
|
|
|
385
389
|
params do
|
|
386
390
|
optional :new_name,
|
|
387
|
-
type:
|
|
391
|
+
type: TrimmedString,
|
|
388
392
|
db_identifier: true,
|
|
389
|
-
prompt: "Enter the new name of the table. " +
|
|
393
|
+
prompt: "Enter the new name of the table. " +
|
|
394
|
+
Webhookdb::DBAdapter::INVALID_IDENTIFIER_PROMPT +
|
|
395
|
+
"\nTable name:"
|
|
390
396
|
end
|
|
391
397
|
post :rename_table do
|
|
392
398
|
org = lookup_org!
|
|
@@ -6,6 +6,8 @@ require "webhookdb/api"
|
|
|
6
6
|
require "webhookdb/admin_api"
|
|
7
7
|
|
|
8
8
|
class Webhookdb::API::Subscriptions < Webhookdb::API::V1
|
|
9
|
+
include Webhookdb::Service::Types
|
|
10
|
+
|
|
9
11
|
resource :organizations do
|
|
10
12
|
route_param :org_identifier, type: String do
|
|
11
13
|
resource :subscriptions do
|
|
@@ -19,7 +21,7 @@ class Webhookdb::API::Subscriptions < Webhookdb::API::V1
|
|
|
19
21
|
|
|
20
22
|
desc "Authenticates stripe user and returns stripe checkout session or billing portal url"
|
|
21
23
|
params do
|
|
22
|
-
optional :plan, type:
|
|
24
|
+
optional :plan, type: TrimmedString
|
|
23
25
|
optional :guard_confirm
|
|
24
26
|
end
|
|
25
27
|
post :open_portal do
|
|
@@ -5,6 +5,8 @@ require "webhookdb/jobs/sync_target_run_sync"
|
|
|
5
5
|
|
|
6
6
|
# rubocop:disable Layout/LineLength
|
|
7
7
|
class Webhookdb::API::SyncTargets < Webhookdb::API::V1
|
|
8
|
+
include Webhookdb::Service::Types
|
|
9
|
+
|
|
8
10
|
class ConnectionUrlType < Grape::Validations::Validators::Base
|
|
9
11
|
def validate!(params)
|
|
10
12
|
url = params[:connection_url]
|
|
@@ -46,14 +48,14 @@ class Webhookdb::API::SyncTargets < Webhookdb::API::V1
|
|
|
46
48
|
disable: ->(req) { req.path.end_with?("/update") },
|
|
47
49
|
}
|
|
48
50
|
is_db && optional(:schema,
|
|
49
|
-
type:
|
|
51
|
+
type: TrimmedString,
|
|
50
52
|
db_identifier: true,
|
|
51
53
|
allow_blank: true,
|
|
52
54
|
desc: "Schema (or namespace) to write the table into. Default to no schema/namespace.",)
|
|
53
55
|
# The description here says there is a default value, but the default value isn't actually saved to the SyncTarget
|
|
54
56
|
# object--it's inferred in the SyncTarget sync behavior when the table value is a blank string.
|
|
55
57
|
is_db && optional(:table,
|
|
56
|
-
type:
|
|
58
|
+
type: TrimmedString,
|
|
57
59
|
db_identifier: true,
|
|
58
60
|
allow_blank: true,
|
|
59
61
|
desc: "Table to create and update. Default to match the table name of the service integration.",)
|
|
@@ -64,7 +66,7 @@ class Webhookdb::API::SyncTargets < Webhookdb::API::V1
|
|
|
64
66
|
end
|
|
65
67
|
params :connection_url do
|
|
66
68
|
optional :connection_url,
|
|
67
|
-
type:
|
|
69
|
+
type: TrimmedString,
|
|
68
70
|
prompt: "Enter the #{is_db ? 'database connection string' : 'HTTP endpoint'} that WebhookDB should sync data to:",
|
|
69
71
|
connection_url_type: is_db ? "db" : "http"
|
|
70
72
|
end
|
|
@@ -112,7 +114,7 @@ class Webhookdb::API::SyncTargets < Webhookdb::API::V1
|
|
|
112
114
|
params do
|
|
113
115
|
use :connection_url
|
|
114
116
|
use :sync_target_params
|
|
115
|
-
requires :service_integration_identifier, type:
|
|
117
|
+
requires :service_integration_identifier, type: TrimmedString, allow_blank: false
|
|
116
118
|
end
|
|
117
119
|
route_setting :target_type, target_type_resource
|
|
118
120
|
post :create do
|
|
@@ -153,8 +155,8 @@ class Webhookdb::API::SyncTargets < Webhookdb::API::V1
|
|
|
153
155
|
end
|
|
154
156
|
end
|
|
155
157
|
params do
|
|
156
|
-
optional :user, type:
|
|
157
|
-
optional :password, type:
|
|
158
|
+
optional :user, type: TrimmedString, prompt: "Username for the connection:"
|
|
159
|
+
optional :password, type: TrimmedString, prompt: "Password for the connection:"
|
|
158
160
|
end
|
|
159
161
|
route_setting :target_type, target_type_resource
|
|
160
162
|
post :update_credentials do
|
|
@@ -187,7 +189,7 @@ class Webhookdb::API::SyncTargets < Webhookdb::API::V1
|
|
|
187
189
|
end
|
|
188
190
|
|
|
189
191
|
params do
|
|
190
|
-
optional :confirm, type:
|
|
192
|
+
optional :confirm, type: TrimmedString
|
|
191
193
|
end
|
|
192
194
|
route_setting :target_type, target_type_resource
|
|
193
195
|
post :delete do
|
data/lib/webhookdb/api/system.rb
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require "webhookdb/api"
|
|
4
4
|
|
|
5
5
|
class Webhookdb::API::WebhookSubscriptions < Webhookdb::API::V1
|
|
6
|
+
include Webhookdb::Service::Types
|
|
7
|
+
|
|
6
8
|
resource :organizations do
|
|
7
9
|
route_param :org_identifier, type: String do
|
|
8
10
|
resource :webhook_subscriptions do
|
|
@@ -21,7 +23,7 @@ class Webhookdb::API::WebhookSubscriptions < Webhookdb::API::V1
|
|
|
21
23
|
|
|
22
24
|
params do
|
|
23
25
|
optional :service_integration_identifier,
|
|
24
|
-
type:
|
|
26
|
+
type: TrimmedString,
|
|
25
27
|
desc: "If provided, attach the webhook subscription to this integration rather than the org.",
|
|
26
28
|
prompt: "Which integration is this for? Use the service name, table name, or opaque id.\n" \
|
|
27
29
|
"See your integrations with `webhookdb integrations list`:"
|
data/lib/webhookdb/apps.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "grape"
|
|
4
4
|
require "grape-swagger"
|
|
5
|
+
require "rack/dynamic_config_writer"
|
|
6
|
+
require "rack/spa_app"
|
|
5
7
|
require "sidekiq/web"
|
|
6
8
|
require "sidekiq/cron/web"
|
|
7
9
|
|
|
@@ -18,6 +20,7 @@ require "webhookdb/api/me"
|
|
|
18
20
|
require "webhookdb/api/organizations"
|
|
19
21
|
require "webhookdb/api/replay"
|
|
20
22
|
require "webhookdb/api/saved_queries"
|
|
23
|
+
require "webhookdb/api/saved_views"
|
|
21
24
|
require "webhookdb/api/service_integrations"
|
|
22
25
|
require "webhookdb/api/services"
|
|
23
26
|
require "webhookdb/api/stripe"
|
|
@@ -27,14 +30,16 @@ require "webhookdb/api/system"
|
|
|
27
30
|
require "webhookdb/api/webhook_subscriptions"
|
|
28
31
|
|
|
29
32
|
require "webhookdb/admin_api/auth"
|
|
30
|
-
require "webhookdb/admin_api/customers"
|
|
31
33
|
require "webhookdb/admin_api/database_documents"
|
|
32
|
-
require "webhookdb/admin_api/
|
|
33
|
-
require "webhookdb/admin_api/roles"
|
|
34
|
+
require "webhookdb/admin_api/data_provider"
|
|
34
35
|
|
|
35
36
|
require "webterm/apps"
|
|
36
37
|
|
|
37
38
|
module Webhookdb::Apps
|
|
39
|
+
REDIRECTS = {
|
|
40
|
+
"/increase" => "/v1/install/increase",
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
38
43
|
# Call this from your rackup file, like config.ru.
|
|
39
44
|
#
|
|
40
45
|
# @example
|
|
@@ -48,15 +53,22 @@ module Webhookdb::Apps
|
|
|
48
53
|
def self.rack_up(config_ru)
|
|
49
54
|
Webhookdb::Async.setup_web
|
|
50
55
|
config_ru.instance_exec do
|
|
51
|
-
map "/
|
|
56
|
+
map "/admin_api" do
|
|
52
57
|
run Webhookdb::Apps::AdminAPI.build_app
|
|
53
58
|
end
|
|
59
|
+
map "/admin" do
|
|
60
|
+
run Webhookdb::Apps::Admin.to_app
|
|
61
|
+
end
|
|
54
62
|
map "/sidekiq" do
|
|
55
63
|
run Webhookdb::Apps::SidekiqWeb.to_app
|
|
56
64
|
end
|
|
57
65
|
map "/terminal" do
|
|
58
66
|
run Webhookdb::Apps::Webterm.to_app
|
|
59
67
|
end
|
|
68
|
+
use Rack::SimpleRedirect, routes: (REDIRECTS.each_with_object({}) do |(k, v), memo|
|
|
69
|
+
memo[k] = v
|
|
70
|
+
memo["#{k}/"] = v
|
|
71
|
+
end)
|
|
60
72
|
run Webhookdb::Apps::API.build_app
|
|
61
73
|
end
|
|
62
74
|
end
|
|
@@ -70,6 +82,7 @@ module Webhookdb::Apps
|
|
|
70
82
|
mount Webhookdb::API::Organizations
|
|
71
83
|
mount Webhookdb::API::Replay
|
|
72
84
|
mount Webhookdb::API::SavedQueries
|
|
85
|
+
mount Webhookdb::API::SavedViews
|
|
73
86
|
mount Webhookdb::API::ServiceIntegrations
|
|
74
87
|
mount Webhookdb::API::Services
|
|
75
88
|
mount Webhookdb::API::Stripe
|
|
@@ -83,12 +96,22 @@ module Webhookdb::Apps
|
|
|
83
96
|
class AdminAPI < Webhookdb::Service
|
|
84
97
|
mount Webhookdb::AdminAPI::Auth
|
|
85
98
|
mount Webhookdb::AdminAPI::DatabaseDocuments
|
|
86
|
-
mount Webhookdb::AdminAPI::
|
|
87
|
-
mount Webhookdb::AdminAPI::Roles
|
|
88
|
-
mount Webhookdb::AdminAPI::Customers
|
|
99
|
+
mount Webhookdb::AdminAPI::DataProvider
|
|
89
100
|
add_swagger_documentation if ENV["RACK_ENV"] == "development"
|
|
90
101
|
end
|
|
91
102
|
|
|
103
|
+
Admin = Rack::Builder.new do
|
|
104
|
+
build_dir = Pathname(__FILE__).dirname.parent.parent + "admin-dist"
|
|
105
|
+
dw = Rack::DynamicConfigWriter.new(build_dir + "index.html", global_assign: "window.whdbDynamicEnv")
|
|
106
|
+
env = {
|
|
107
|
+
"VITE_API_ROOT" => "/",
|
|
108
|
+
"VITE_RELEASE" => "admin@1.0.0",
|
|
109
|
+
"NODE_ENV" => "production",
|
|
110
|
+
}.merge(Rack::DynamicConfigWriter.pick_env("VITE_"))
|
|
111
|
+
index_bytes = dw.as_string(env)
|
|
112
|
+
Rack::SpaApp.run_spa_app(self, build_dir, enforce_ssl: Webhookdb::Service.enforce_ssl, index_bytes:)
|
|
113
|
+
end
|
|
114
|
+
|
|
92
115
|
SidekiqWeb = Rack::Builder.new do
|
|
93
116
|
use Sentry::Rack::CaptureExceptions if Webhookdb::Sentry.enabled?
|
|
94
117
|
use Rack::Auth::Basic, "Protected Area" do |username, password|
|
|
@@ -11,6 +11,8 @@ class Webhookdb::Async::AuditLogger < Amigo::AuditLogger
|
|
|
11
11
|
MAX_STR_LEN = 64
|
|
12
12
|
STR_PREFIX_LEN = 12
|
|
13
13
|
|
|
14
|
+
def audit_log_level = Webhookdb::Async.audit_log_level
|
|
15
|
+
|
|
14
16
|
def perform(event_json)
|
|
15
17
|
j2 = event_json.dup
|
|
16
18
|
j2["payload"] = self.trim_long_strings(j2["payload"], max_str_len: MAX_STR_LEN, str_prefix_len: STR_PREFIX_LEN)
|
data/lib/webhookdb/async.rb
CHANGED
|
@@ -27,6 +27,11 @@ module Webhookdb::Async
|
|
|
27
27
|
# at `warn` level.
|
|
28
28
|
setting :slow_job_seconds, 1.0
|
|
29
29
|
|
|
30
|
+
# The log level that Webhookdb::Async::AuditLogger logs at.
|
|
31
|
+
# By default, use :info, but :debug may be appropriate for higher-activity servers
|
|
32
|
+
# to reduce logging costs (the messages can be big).
|
|
33
|
+
setting :audit_log_level, :info
|
|
34
|
+
|
|
30
35
|
setting :sidekiq_redis_url, "redis://localhost:6379/0", key: "REDIS_URL"
|
|
31
36
|
setting :sidekiq_redis_provider, ""
|
|
32
37
|
# For sidekiq web UI. Randomize a default so they will only be useful if set.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Helper table so backfill jobs can take exclusive locks on a service integration.
|
|
4
|
+
# Otherwise we end up backfilling the same integration concurrently.
|
|
5
|
+
class Webhookdb::BackfillJob::ServiceIntegrationLock < Webhookdb::Postgres::Model(
|
|
6
|
+
:backfill_job_service_integration_locks,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
many_to_one :service_integration, class: "Webhookdb::ServiceIntegration"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Table: backfill_job_service_integration_locks
|
|
13
|
+
# -------------------------------------------------------------------------------------------------------------------------------------------------
|
|
14
|
+
# Columns:
|
|
15
|
+
# id | integer | PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
|
|
16
|
+
# service_integration_id | integer | NOT NULL
|
|
17
|
+
# Indexes:
|
|
18
|
+
# backfill_job_service_integration_locks_pkey | PRIMARY KEY btree (id)
|
|
19
|
+
# backfill_job_service_integration_loc_service_integration_id_key | UNIQUE btree (service_integration_id)
|
|
20
|
+
# Foreign key constraints:
|
|
21
|
+
# backfill_job_service_integration_lo_service_integration_id_fkey | (service_integration_id) REFERENCES service_integrations(id) ON DELETE CASCADE
|
|
22
|
+
# -------------------------------------------------------------------------------------------------------------------------------------------------
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#
|
|
16
16
|
class Webhookdb::BackfillJob < Webhookdb::Postgres::Model(:backfill_jobs)
|
|
17
17
|
plugin :timestamps
|
|
18
|
+
plugin :text_searchable, terms: [:service_integration]
|
|
18
19
|
|
|
19
20
|
many_to_one :service_integration, class: "Webhookdb::ServiceIntegration"
|
|
20
21
|
many_to_one :parent_job, class: "Webhookdb::BackfillJob"
|
|
@@ -71,6 +72,12 @@ class Webhookdb::BackfillJob < Webhookdb::Postgres::Model(:backfill_jobs)
|
|
|
71
72
|
self.child_jobs.each(&:enqueue)
|
|
72
73
|
end
|
|
73
74
|
|
|
75
|
+
def ensure_service_integration_lock
|
|
76
|
+
return Webhookdb::BackfillJob::ServiceIntegrationLock.find_or_create_or_find(
|
|
77
|
+
service_integration_id: self.service_integration_id,
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
74
81
|
#
|
|
75
82
|
# :section: Sequel Hooks
|
|
76
83
|
#
|
|
@@ -93,6 +100,8 @@ end
|
|
|
93
100
|
# parent_job_id | integer |
|
|
94
101
|
# created_by_id | integer |
|
|
95
102
|
# incremental | boolean | NOT NULL
|
|
103
|
+
# criteria | jsonb | NOT NULL DEFAULT '{}'::jsonb
|
|
104
|
+
# text_search | tsvector |
|
|
96
105
|
# Indexes:
|
|
97
106
|
# backfill_jobs_pkey | PRIMARY KEY btree (id)
|
|
98
107
|
# backfill_jobs_opaque_id_key | UNIQUE btree (opaque_id)
|
data/lib/webhookdb/customer.rb
CHANGED
|
@@ -37,6 +37,7 @@ class Webhookdb::Customer < Webhookdb::Postgres::Model(:customers)
|
|
|
37
37
|
|
|
38
38
|
plugin :timestamps
|
|
39
39
|
plugin :soft_deletes
|
|
40
|
+
plugin :text_searchable, terms: [:name, :email]
|
|
40
41
|
|
|
41
42
|
one_to_many :all_memberships, class: "Webhookdb::OrganizationMembership"
|
|
42
43
|
one_to_many :invited_memberships,
|
|
@@ -329,6 +330,7 @@ end
|
|
|
329
330
|
# name | text | NOT NULL DEFAULT ''::text
|
|
330
331
|
# note | text | NOT NULL DEFAULT ''::text
|
|
331
332
|
# opaque_id | text | NOT NULL
|
|
333
|
+
# text_search | tsvector |
|
|
332
334
|
# Indexes:
|
|
333
335
|
# customers_pkey | PRIMARY KEY btree (id)
|
|
334
336
|
# customers_email_key | UNIQUE btree (email)
|
|
@@ -339,9 +341,12 @@ end
|
|
|
339
341
|
# backfill_jobs | backfill_jobs_created_by_id_fkey | (created_by_id) REFERENCES customers(id) ON DELETE SET NULL
|
|
340
342
|
# customer_reset_codes | customer_reset_codes_customer_id_fkey | (customer_id) REFERENCES customers(id) ON DELETE CASCADE
|
|
341
343
|
# message_deliveries | message_deliveries_recipient_id_fkey | (recipient_id) REFERENCES customers(id) ON DELETE SET NULL
|
|
344
|
+
# oauth_sessions | oauth_sessions_customer_id_fkey | (customer_id) REFERENCES customers(id) ON DELETE CASCADE
|
|
342
345
|
# organization_database_migrations | organization_database_migrations_started_by_id_fkey | (started_by_id) REFERENCES customers(id) ON DELETE SET NULL
|
|
343
346
|
# organization_memberships | organization_memberships_customer_id_fkey | (customer_id) REFERENCES customers(id)
|
|
344
347
|
# roles_customers | roles_customers_customer_id_fkey | (customer_id) REFERENCES customers(id)
|
|
348
|
+
# saved_queries | saved_queries_created_by_id_fkey | (created_by_id) REFERENCES customers(id) ON DELETE SET NULL
|
|
349
|
+
# saved_views | saved_views_created_by_id_fkey | (created_by_id) REFERENCES customers(id) ON DELETE SET NULL
|
|
345
350
|
# sync_targets | sync_targets_created_by_id_fkey | (created_by_id) REFERENCES customers(id) ON DELETE SET NULL
|
|
346
351
|
# webhook_subscriptions | webhook_subscriptions_created_by_id_fkey | (created_by_id) REFERENCES customers(id)
|
|
347
352
|
# -----------------------------------------------------------------------------------------------------------------------------------------------------
|
|
@@ -52,7 +52,7 @@ class Webhookdb::DatabaseDocument < Webhookdb::Postgres::Model(:database_documen
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def presigned_view_url(expire_at:, **kw)
|
|
55
|
-
url = "#{Webhookdb.api_url}/
|
|
55
|
+
url = "#{Webhookdb.api_url}/admin_api/v1/database_documents/#{self.id}/view"
|
|
56
56
|
return self.sign_url(url, expire_at:, **kw)
|
|
57
57
|
end
|
|
58
58
|
end
|
|
@@ -28,7 +28,7 @@ module Webhookdb::DBAdapter::DefaultSql
|
|
|
28
28
|
def escape_identifier(s)
|
|
29
29
|
s = s.to_s
|
|
30
30
|
raise ArgumentError, "#{s} is an invalid identifier and should have been validated previously" unless
|
|
31
|
-
Webhookdb::DBAdapter
|
|
31
|
+
Webhookdb::DBAdapter.valid_identifier?(s)
|
|
32
32
|
|
|
33
33
|
quo = self.identifier_quote_char
|
|
34
34
|
return "#{quo}#{s}#{quo}" if RESERVED_KEYWORDS.include?(s.upcase) ||
|
data/lib/webhookdb/db_adapter.rb
CHANGED
|
@@ -6,10 +6,14 @@ class Webhookdb::DBAdapter
|
|
|
6
6
|
class UnsupportedAdapter < StandardError; end
|
|
7
7
|
|
|
8
8
|
VALID_IDENTIFIER = /^[a-zA-Z][a-zA-Z\d_ ]*$/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
INVALID_IDENTIFIER_PROMPT =
|
|
10
|
+
"Identifiers must start with a letter and contain only letters, numbers, spaces, and underscores.\n" \
|
|
11
|
+
"See https://docs.webhookdb.com/concepts/valid-identifiers/ for rules\n" \
|
|
12
|
+
"about identifiers like schema, table, and column names."
|
|
13
|
+
|
|
14
|
+
INVALID_IDENTIFIER_MESSAGE = INVALID_IDENTIFIER_PROMPT.tr("\n", " ")
|
|
15
|
+
|
|
16
|
+
class InvalidIdentifier < Webhookdb::InvalidInput; end
|
|
13
17
|
|
|
14
18
|
class Schema < Webhookdb::TypedStruct
|
|
15
19
|
attr_reader :name
|
|
@@ -202,6 +206,18 @@ class Webhookdb::DBAdapter
|
|
|
202
206
|
def self.supported_adapters_message
|
|
203
207
|
return "Postgres (postgres://), SnowflakeDB (snowflake://)"
|
|
204
208
|
end
|
|
209
|
+
|
|
210
|
+
def self.valid_identifier?(s) = VALID_IDENTIFIER.match?(s)
|
|
211
|
+
|
|
212
|
+
# Raise if the identifier +s+ is invalid according to +VALID_IDENTIFIER+.
|
|
213
|
+
# +type+ is used in the error message, like 'Sorry, this is not a valid table name.'
|
|
214
|
+
# If the user tries SQL injection, let them know we noticed!
|
|
215
|
+
def self.validate_identifier!(s, type:)
|
|
216
|
+
return if self.valid_identifier?(s)
|
|
217
|
+
msg = "Sorry, this is not a valid #{type} name. #{INVALID_IDENTIFIER_MESSAGE}"
|
|
218
|
+
msg += " And we see you what you did there ;)" if s.include?(";") && s.downcase.include?("drop")
|
|
219
|
+
raise InvalidIdentifier, msg
|
|
220
|
+
end
|
|
205
221
|
end
|
|
206
222
|
|
|
207
223
|
require "webhookdb/db_adapter/pg"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/fixtures"
|
|
4
|
+
|
|
5
|
+
module Webhookdb::Fixtures::MessageBody
|
|
6
|
+
extend Webhookdb::Fixtures
|
|
7
|
+
|
|
8
|
+
fixtured_class Webhookdb::Message::Body
|
|
9
|
+
|
|
10
|
+
base :message_body do
|
|
11
|
+
self.mediatype ||= "text/plain"
|
|
12
|
+
self.content ||= Faker::Lorem.paragraph
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
before_saving do |instance|
|
|
16
|
+
instance.delivery ||= Webhookdb::Fixtures.message_delivery.create
|
|
17
|
+
instance
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
decorator :html do
|
|
21
|
+
self.mediatype = "text/html"
|
|
22
|
+
self.content = "<html><body><p>#{Faker::Lorem.sentence}</p></body></html>"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
decorator :text do
|
|
26
|
+
self.mediatype = "text/plain"
|
|
27
|
+
self.content = Faker::Lorem.paragraph
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
decorator :subject do
|
|
31
|
+
self.mediatype = "subject"
|
|
32
|
+
self.content = Faker::Lorem.sentence
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -20,6 +20,11 @@ module Webhookdb::Fixtures::Organizations
|
|
|
20
20
|
Webhookdb::Fixtures.organization_membership.verified.create(customer: c, organization: self)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
decorator :with_admin, presave: true do |c={}|
|
|
24
|
+
c = Webhookdb::Fixtures.customer.create(c) unless c.is_a?(Webhookdb::Customer)
|
|
25
|
+
Webhookdb::Fixtures.organization_membership.verified.admin.create(customer: c, organization: self)
|
|
26
|
+
end
|
|
27
|
+
|
|
23
28
|
decorator :with_invite, presave: true do |c={}|
|
|
24
29
|
c = Webhookdb::Fixtures.customer.create(c) unless c.is_a?(Webhookdb::Customer)
|
|
25
30
|
Webhookdb::Fixtures.organization_membership.invite.create(customer: c, organization: self)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb"
|
|
4
|
+
require "webhookdb/fixtures"
|
|
5
|
+
|
|
6
|
+
module Webhookdb::Fixtures::Roles
|
|
7
|
+
extend Webhookdb::Fixtures
|
|
8
|
+
|
|
9
|
+
fixtured_class Webhookdb::Role
|
|
10
|
+
|
|
11
|
+
base :role do
|
|
12
|
+
self.name ||= Faker::Lorem.word + SecureRandom.hex(2)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb"
|
|
4
|
+
require "webhookdb/fixtures"
|
|
5
|
+
|
|
6
|
+
module Webhookdb::Fixtures::SavedViews
|
|
7
|
+
extend Webhookdb::Fixtures
|
|
8
|
+
|
|
9
|
+
fixtured_class Webhookdb::SavedView
|
|
10
|
+
|
|
11
|
+
base :saved_view do
|
|
12
|
+
self.name ||= "testview_#{SecureRandom.hex(3)}"
|
|
13
|
+
self.sql ||= "SELECT 'fixtured' AS testcol"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
before_saving do |instance|
|
|
17
|
+
instance.organization ||= Webhookdb::Fixtures.organization.create
|
|
18
|
+
instance
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
decorator :created_by do |c={}|
|
|
22
|
+
c = Webhookdb::Fixtures.customer.create(c) unless c.is_a?(Webhookdb::Customer)
|
|
23
|
+
self.created_by = c
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "webhookdb/fixtures"
|
|
4
|
+
|
|
5
|
+
module Webhookdb::Fixtures::WebhookSubscriptionDeliveries
|
|
6
|
+
extend Webhookdb::Fixtures
|
|
7
|
+
|
|
8
|
+
fixtured_class Webhookdb::WebhookSubscription::Delivery
|
|
9
|
+
|
|
10
|
+
base :webhook_subscription_delivery do
|
|
11
|
+
self.payload ||= {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
before_saving do |instance|
|
|
15
|
+
instance.webhook_subscription ||= Webhookdb::Fixtures.webhook_subscription.create
|
|
16
|
+
instance
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/webhookdb/http.rb
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
|
|
3
|
+
require "appydays/configurable"
|
|
5
4
|
require "appydays/loggable/httparty_formatter"
|
|
5
|
+
require "httparty"
|
|
6
6
|
|
|
7
7
|
module Webhookdb::Http
|
|
8
|
+
include Appydays::Configurable
|
|
9
|
+
configurable(:http) do
|
|
10
|
+
setting :log_level, :debug
|
|
11
|
+
end
|
|
12
|
+
|
|
8
13
|
# Error raised when some API has rate limited us.
|
|
9
14
|
class BaseError < StandardError; end
|
|
10
15
|
|
|
@@ -88,6 +93,7 @@ module Webhookdb::Http
|
|
|
88
93
|
|
|
89
94
|
raise ArgumentError, "must pass :logger keyword" unless options.key?(:logger)
|
|
90
95
|
options[:log_format] = :appydays
|
|
96
|
+
options[:log_level] = self.log_level
|
|
91
97
|
end
|
|
92
98
|
|
|
93
99
|
# Convenience wrapper around Down that handles gzip.
|
data/lib/webhookdb/icalendar.rb
CHANGED
|
@@ -19,5 +19,8 @@ module Webhookdb::Icalendar
|
|
|
19
19
|
# or two threads for 7 hours. The resyncs are spread out across the sync period
|
|
20
20
|
# (ie, no thundering herd every 8 hours), but it is still a good idea to sync as infrequently as possible.
|
|
21
21
|
setting :sync_period_hours, 6
|
|
22
|
+
|
|
23
|
+
# Cancelled events that were cancelled this long ago are deleted from the database.
|
|
24
|
+
setting :stale_cancelled_event_threshold_days, 35
|
|
22
25
|
end
|
|
23
26
|
end
|