Module: Webhookdb
- Extended by:
- MethodUtilities
- Includes:
- Appydays::Configurable, Appydays::Loggable
- Defined in:
- lib/webhookdb/json.rb,
lib/webhookdb/version.rb,
lib/webhookdb/envfixer.rb,
lib/webhookdb.rb
Defined Under Namespace
Modules: API, AWS, Admin, AdminAPI, Apps, Async, Console, Crypto, Dbutil, DemoMode, EmailOctopus, Enumerable, Envfixer, Fixtures, Formatting, Front, GoogleCalendar, Http, Icalendar, Id, IntegrationSpecHelpers, Intercom, Jobs, Json, Liquid, Message, Messages, MethodUtilities, MicrosoftCalendar, Nextpax, Oauth, PhoneNumber, Plaid, Platform, Plivo, Postgres, Postmark, Pry, Redis, Sentry, Signalwire, SpecHelpers, Sponsy, Tasks, Theranest, Transistor, Twilio, WindowsTZ Classes: AggregateResult, BackfillJob, Backfiller, Cloudflare, ConnectionCache, Convertkit, Customer, DBAdapter, DatabaseDocument, DatabaseLocked, DeveloperAlert, Github, Heroku, Idempotency, Increase, InvalidInput, InvalidPostcondition, InvalidPrecondition, InvariantViolation, LockFailed, LoggedWebhook, Organization, OrganizationMembership, RegressionModeSkip, Replicator, Role, SavedQuery, SavedView, Service, ServiceIntegration, Shopify, Slack, Snowflake, Stripe, Subscription, SyncTarget, TypedStruct, WebhookResponse, WebhookSubscription, Webterm, Xml
Constant Summary collapse
- VERSION =
"1.3.1"
- APPLICATION_NAME =
"Webhookdb"
- RACK_ENV =
Appydays::Configurable.fetch_env(["RACK_ENV", "RUBY_ENV"], "development")
- COMMIT =
Appydays::Configurable.fetch_env(["COMMIT", "GIT_SHA", "HEROKU_SLUG_COMMIT"], "00000000")
- RELEASE =
Appydays::Configurable.fetch_env(["RELEASE", "GIT_REF", "HEROKU_RELEASE_VERSION"], "unknown-release")
- RELEASE_CREATED_AT =
Appydays::Configurable.fetch_env( ["RELEASE_CREATED_AT", "BUILT_AT", "HEROKU_RELEASE_CREATED_AT"], Time.at(0).utc.iso8601, )
- INTEGRATION_TESTS_ENABLED =
ENV.fetch("INTEGRATION_TESTS", false)
- DATA_DIR =
Pathname(__FILE__).dirname.parent + "data"
- NUMBERS_TO_WORDS =
{ "0" => "zero", "1" => "one", "2" => "two", "3" => "three", "4" => "four", "5" => "five", "6" => "six", "7" => "seven", "8" => "eight", "9" => "nine", }.freeze
Class Method Summary collapse
-
.cached_get(key) ⇒ Object
If globals caching is enabled, see if there is a cached value under
key
and return it if so. -
.idempotency_key(instance, *parts) ⇒ Object
Generate a key for the specified Sequel model
instance
and any additionalparts
that can be used for idempotent requests. - .load_app ⇒ Object
- .parse_bool(s) ⇒ Object
-
.regression_mode? ⇒ Boolean
Regression mode is true when we re replaying webhooks locally, or for some other reason, want to disable certain checks we use in production.
-
.request_user_and_admin ⇒ Object
Return the request user and admin stored in TLS.
-
.set_request_user_and_admin(user, admin, &block) ⇒ Object
Return the request user stored in TLS.
-
.to_slug(s) ⇒ Object
Convert a string into something we consistently use for slugs: a-z, 0-9, and underscores only.
Methods included from MethodUtilities
attr_predicate, attr_predicate_accessor, singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer, singleton_method_alias, singleton_predicate_accessor, singleton_predicate_reader
Class Method Details
.cached_get(key) ⇒ Object
If globals caching is enabled, see if there is a cached value under key
and return it if so. If there is not, evaluate the given block and store that value. Generally used for looking up well-known database objects like certain roles.
123 124 125 126 127 128 129 130 131 |
# File 'lib/webhookdb.rb', line 123 def self.cached_get(key) if self.use_globals_cache result = self.globals_cache[key] return result if result end result = yield() (self.globals_cache[key] = result) if self.use_globals_cache return result end |
.idempotency_key(instance, *parts) ⇒ Object
Generate a key for the specified Sequel model instance
and any additional parts
that can be used for idempotent requests.
141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/webhookdb.rb', line 141 def self.idempotency_key(instance, *parts) key = "%s-%s" % [instance.class.implicit_table_name, instance.pk] if instance.respond_to?(:updated_at) && instance.updated_at parts << instance.updated_at elsif instance.respond_to?(:created_at) && instance.created_at parts << instance.created_at end parts << SecureRandom.hex(8) if self.bust_idempotency key << "-" << parts.map(&:to_s).join("-") unless parts.empty? return key end |
.load_app ⇒ Object
106 107 108 109 110 111 112 113 114 |
# File 'lib/webhookdb.rb', line 106 def self.load_app $stdout.sync = true $stderr.sync = true Appydays::Loggable.configure_12factor(format: self.log_format, application: APPLICATION_NAME) require "webhookdb/postgres" Webhookdb::Postgres.load_models end |
.parse_bool(s) ⇒ Object
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/webhookdb.rb', line 182 def self.parse_bool(s) # rubocop:disable Style/NumericPredicate return false if s == nil? || s.blank? || s == 0 # rubocop:enable Style/NumericPredicate return true if s.is_a?(Integer) sb = s.to_s.downcase return true if ["true", "t", "yes", "y", "on", "1"].include?(sb) return false if ["false", "f", "no", "n", "off", "0"].include?(sb) raise ArgumentError, "unparseable bool: #{s.inspect}" end |
.regression_mode? ⇒ Boolean
Regression mode is true when we re replaying webhooks locally, or for some other reason, want to disable certain checks we use in production. For example, we may want to ignore certain errors (like if integrations are missing dependency rows), or disable certain validations (like always assume the webhook is valid).
100 101 102 |
# File 'lib/webhookdb.rb', line 100 def self.regression_mode? return self.regression_mode end |
.request_user_and_admin ⇒ Object
Return the request user and admin stored in TLS. See service.rb for implementation.
Note that the second return value (the admin) will be nil if not authed as an admin, and if an admin is impersonating, the impersonated customer is the first value.
Both values will be nil if no user is authed or this is called outside of a request.
Usually these fields should only be used where it would be sufficiently difficult to pass the current user through the stack. In the API, you should instead use the ‘current customer’ methods like current_customer, and admin_customer, NOT using TLS. Outside of the API, this should only be used for things like auditing; it should NOT, for example, ever be used to determine the ‘customer owner’ of objects being created. Nearly all code will be simpler if the current customer is passed around. But it would be too complex for some code (like auditing) so this system exists. Overuse of request_user_and_admin will inevitably lead to regret.
209 210 211 |
# File 'lib/webhookdb.rb', line 209 def self.request_user_and_admin return Thread.current[:request_user], Thread.current[:request_admin] end |
.set_request_user_and_admin(user, admin, &block) ⇒ Object
Return the request user stored in TLS. See service.rb for details.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/webhookdb.rb', line 214 def self.set_request_user_and_admin(user, admin, &block) if !user.nil? && !admin.nil? && self.request_user_and_admin != [nil, nil] raise Webhookdb::InvalidPrecondition, "request user is already set: #{user}, #{admin}" end Thread.current[:request_user] = user Thread.current[:request_admin] = admin return if block.nil? begin yield ensure Thread.current[:request_user] = nil Thread.current[:request_admin] = nil end end |
.to_slug(s) ⇒ Object
Convert a string into something we consistently use for slugs: a-z, 0-9, and underscores only. Leading numbers are converted to words.
Acme + Corporation -> “acme_corporation” 1Byte -> “one_byte” 10Byte -> “one0_byte”
161 162 163 164 165 166 167 |
# File 'lib/webhookdb.rb', line 161 def self.to_slug(s) raise ArgumentError, "s cannot be nil" if s.nil? return "" if s.blank? slug = s.downcase.strip.gsub(/[^a-z0-9]/, "_").squeeze("_") slug = NUMBERS_TO_WORDS[slug.first] + slug[1..] if slug.first.match?(/[0-9]/) return slug end |