Module: Webhookdb
- Extended by:
- MethodUtilities
- Includes:
- Appydays::Configurable, Appydays::Loggable
- Defined in:
- lib/webhookdb/json.rb,
lib/webhookdb/version.rb,
lib/webhookdb.rb
Defined Under Namespace
Modules: API, AWS, Admin, AdminAPI, Apps, Async, Console, Crypto, Dbutil, DemoMode, EmailOctopus, Enumerable, 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, Service, ServiceIntegration, Shopify, Slack, Snowflake, Stripe, Subscription, SyncTarget, TypedStruct, WebhookResponse, WebhookSubscription, Webterm, Xml
Constant Summary collapse
- VERSION =
"1.1.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"
- UNAMBIGUOUS_CHARS =
Remove ambiguous characters (L, I, 1 or 0, O) and vowels from possible codes to avoid creating ambiguous codes or real words.
"CDFGHJKMNPQRTVWXYZ23469".chars.freeze
- 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
-
.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.
- .take_unambiguous_chars(n) ⇒ Object
-
.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.
138 139 140 141 142 143 144 145 146 |
# File 'lib/webhookdb.rb', line 138 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 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.
156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/webhookdb.rb', line 156 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
118 119 120 121 122 123 124 125 126 |
# File 'lib/webhookdb.rb', line 118 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 |
.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).
109 110 111 |
# File 'lib/webhookdb.rb', line 109 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.
225 226 227 |
# File 'lib/webhookdb.rb', line 225 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.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/webhookdb.rb', line 230 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 |
.take_unambiguous_chars(n) ⇒ Object
178 179 180 |
# File 'lib/webhookdb.rb', line 178 def self.take_unambiguous_chars(n) return Array.new(n) { UNAMBIGUOUS_CHARS.sample }.join 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”
188 189 190 191 192 193 194 |
# File 'lib/webhookdb.rb', line 188 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 |