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, Errors, 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, ExceptionCarrier, Github, Heroku, Idempotency, Increase, InvalidInput, InvalidPostcondition, InvalidPrecondition, InvariantViolation, LockFailed, LoggedWebhook, Organization, OrganizationMembership, ProgrammingError, RegressionModeSkip, Replicator, Role, SavedQuery, SavedView, Service, ServiceIntegration, Shopify, Slack, Snowflake, Stripe, Subscription, SyncTarget, SystemLogEvent, TypedStruct, WebhookResponse, WebhookSubscription, WebhookdbError, Webterm, Xml
Constant Summary collapse
- VERSION =
"1.4.0"
- 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
- .admin_url ⇒ Object
-
.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
.admin_url ⇒ Object
102 |
# File 'lib/webhookdb.rb', line 102 def self.admin_url = self.api_url |
.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.
131 132 133 134 135 136 137 138 139 |
# File 'lib/webhookdb.rb', line 131 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.
165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/webhookdb.rb', line 165 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
114 115 116 117 118 119 120 121 122 |
# File 'lib/webhookdb.rb', line 114 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
206 207 208 209 210 211 212 213 214 215 |
# File 'lib/webhookdb.rb', line 206 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).
108 109 110 |
# File 'lib/webhookdb.rb', line 108 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.
233 234 235 |
# File 'lib/webhookdb.rb', line 233 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.
238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/webhookdb.rb', line 238 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”
185 186 187 188 189 190 191 |
# File 'lib/webhookdb.rb', line 185 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 |