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.0.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"
- 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
keyand return it if so. -
.idempotency_key(instance, *parts) ⇒ Object
Generate a key for the specified Sequel model
instanceand any additionalpartsthat 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.
124 125 126 127 128 129 130 131 132 |
# File 'lib/webhookdb.rb', line 124 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.
142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/webhookdb.rb', line 142 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
104 105 106 107 108 109 110 111 112 |
# File 'lib/webhookdb.rb', line 104 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).
95 96 97 |
# File 'lib/webhookdb.rb', line 95 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.
211 212 213 |
# File 'lib/webhookdb.rb', line 211 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.
216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/webhookdb.rb', line 216 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
164 165 166 |
# File 'lib/webhookdb.rb', line 164 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”
174 175 176 177 178 179 180 |
# File 'lib/webhookdb.rb', line 174 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 |