Class: Parse::Webhooks::Payload
- Inherits:
-
Object
- Object
- Parse::Webhooks::Payload
- Includes:
- ActiveModel::Serializers::JSON
- Defined in:
- lib/parse/webhooks/payload.rb
Overview
Represents the data structure that Parse server sends to a registered webhook.
Parse Parse allows you to receive Cloud Code webhooks on your own hosted
server. The Parse::Webhooks class is a lightweight Rack application that
routes incoming Cloud Code webhook requests and payloads to locally
registered handlers. The payloads are Payload type of objects that
represent that data that Parse sends webhook handlers.
Constant Summary collapse
- ATTRIBUTES =
The set of keys that can be contained in a Parse hash payload for a webhook.
{ master: nil, user: nil, installationId: nil, params: nil, functionName: nil, object: nil, original: nil, update: nil, query: nil, log: nil, objects: nil, triggerName: nil, event: nil, clients: nil, subscriptions: nil, context: nil }.freeze
Instance Attribute Summary collapse
-
#clients ⇒ Integer?
Connection-global metadata sent on the LiveQuery +beforeConnect+ / +afterEvent+ triggers: the number of currently-connected LiveQuery clients.
-
#context ⇒ Hash?
The caller-supplied context object threaded from the originating REST write or cloud-function call via the +X-Parse-Cloud-Context+ header.
-
#event ⇒ String?
The LiveQuery event type for an +afterEvent+ trigger -- one of +"create"+, +"enter"+, +"update"+, +"leave"+, or +"delete"+ -- or +"connect"+ for a +beforeConnect+ trigger.
-
#function_name ⇒ String
(also: #functionName)
The name of the function.
-
#installation_id ⇒ String
(also: #installationId)
The identifier of the device that submitted the request.
-
#log ⇒ Object
The query request in a beforeFind trigger.
-
#master ⇒ Boolean
Whether the master key was used for this request.
-
#object ⇒ Hash
In a beforeSave, this attribute is the final object that will be persisted.
-
#objects ⇒ Object
The query request in a beforeFind trigger.
-
#original ⇒ Hash
In a beforeSave, for previously saved objects, this attribute is the Parse::Object that was previously in the persistent store.
-
#params ⇒ Hash
The list of function arguments submitted for a function request.
-
#query ⇒ Object
The query request in a beforeFind trigger.
-
#raw ⇒ Hash
The raw payload from Parse server.
-
#session_token ⇒ Object
readonly
Returns the value of attribute session_token.
-
#subscriptions ⇒ Integer?
Connection-global metadata sent on the LiveQuery +beforeConnect+ / +afterEvent+ triggers: the number of active subscriptions.
-
#trigger_name ⇒ String
(also: #triggerName)
The name of the trigger (ex. beforeSave, afterSave, etc.).
-
#update ⇒ Hash
The update payload in the request.
-
#user ⇒ Parse::User
The user who performed this request or action.
Instance Method Summary collapse
-
#after_delete? ⇒ Boolean
true if this is a afterDelete webhook trigger request.
-
#after_event? ⇒ Boolean
true if this is a LiveQuery afterEvent webhook trigger request.
-
#after_find? ⇒ Boolean
true if this is a afterFind webhook trigger request.
-
#after_login? ⇒ Boolean
true if this is a afterLogin webhook trigger request.
-
#after_logout? ⇒ Boolean
true if this is a afterLogout webhook trigger request.
-
#after_response { ... } ⇒ Boolean
(also: #defer)
Register a block to run after this webhook's response has been sent to Parse Server, off the client's critical path.
-
#after_save? ⇒ Boolean
true if this is a afterSave webhook trigger request.
-
#after_trigger? ⇒ Boolean
true if this is a afterSave or afterDelete webhook trigger request.
- #attributes ⇒ ATTRIBUTES
-
#auth_trigger? ⇒ Boolean
true if this is one of the authentication-side triggers (beforeLogin / afterLogin / afterLogout / beforePasswordResetRequest).
-
#before_connect? ⇒ Boolean
true if this is a LiveQuery beforeConnect webhook trigger request.
-
#before_delete? ⇒ Boolean
true if this is a beforeDelete webhook trigger request.
-
#before_find? ⇒ Boolean
true if this is a beforeFind webhook trigger request.
-
#before_login? ⇒ Boolean
true if this is a beforeLogin webhook trigger request.
-
#before_password_reset_request? ⇒ Boolean
true if this is a beforePasswordResetRequest webhook trigger request.
-
#before_save? ⇒ Boolean
true if this is a beforeSave webhook trigger request.
-
#before_subscribe? ⇒ Boolean
true if this is a LiveQuery beforeSubscribe webhook trigger request.
-
#before_trigger? ⇒ Boolean
true if this is a beforeSave or beforeDelete webhook trigger request.
-
#client_initiated? ⇒ Boolean
Returns true if this webhook was triggered by a client request (JavaScript, iOS, Android, etc.) This is the inverse of ruby_initiated? and is useful for callback logic that should only run for client-initiated operations.
-
#error!(msg = "") ⇒ Parse::Webhooks::ResponseError
This method will intentionally raise a ResponseError with a specific message.
-
#function? ⇒ Boolean
true if this is a webhook function request.
-
#initialize(hash = {}, webhook_class = nil) ⇒ Payload
constructor
You would normally never create a Payload object since it is automatically provided to you when using Parse::Webhooks.
-
#inspect ⇒ Object
Redacted inspection.
-
#live_query_trigger? ⇒ Boolean
true if this is one of the LiveQuery triggers (beforeConnect / beforeSubscribe / afterEvent).
-
#master? ⇒ Boolean
true if the master key was used for this request.
-
#object? ⇒ Boolean
true if this request is a trigger that contains an object.
-
#original_parse_object ⇒ Parse::Object
A Parse::Object from the original object.
-
#parse_class ⇒ String
The name of the Parse class for this request.
-
#parse_id ⇒ String
(also: #objectId)
The objectId in this request.
-
#parse_object(pristine = false) ⇒ Parse::Object
This method returns a Parse::Object by combining the original object, if was provided, with the final object.
-
#parse_query ⇒ Parse::Query
The Parse query for a beforeFind trigger.
-
#ruby_initiated? ⇒ Boolean
Returns true if this webhook was triggered by a Ruby Parse Stack request.
-
#session_token? ⇒ Boolean
true if this payload carried a caller session token -- i.e.
-
#trigger? ⇒ Boolean
true if this is a webhook trigger request.
-
#user_agent(**opts) ⇒ Parse::Agent?
An opt-in, non-master Agent scoped to the webhook caller's session token.
-
#user_client ⇒ Parse::Client?
An opt-in, user-scoped Client for acting on the server as the webhook's calling user.
-
#wlog(s) ⇒ Object
Method to print to standard that utilizes the an internal id to make it easier to trace incoming requests.
Constructor Details
#initialize(hash = {}, webhook_class = nil) ⇒ Payload
You would normally never create a Parse::Webhooks::Payload object since it is automatically provided to you when using Parse::Webhooks.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/parse/webhooks/payload.rb', line 125 def initialize(hash = {}, webhook_class = nil) hash = JSON.parse(hash, max_nesting: 20) if hash.is_a?(String) hash = Hash[hash.map { |k, v| [k.to_s.underscore.to_sym, v] }] @raw = hash # Set BEFORE the vector scrub below so the route-derived class is # available to strip :vector columns from afterFind objects (whose # body carries no className of its own). @webhook_class = webhook_class.to_s if webhook_class && !webhook_class.to_s.empty? @master = hash[:master] # Capture the caller's session token from the *unscrubbed* user hash # before scrub_credentials strips it below. Parse Server includes # `user.sessionToken` on every trigger fired by a logged-in caller # (it is absent for master-key-originated requests). Pulling it aside # here -- rather than leaving it in @user -- keeps it out of any object # a handler might persist and out of #as_json / the request log, while # still letting a handler opt in to acting as the calling user via # #session_token / #user_client / #user_agent. @session_token = self.class.extract_session_token(hash[:user]) # LiveQuery beforeConnect/beforeSubscribe carry the caller's session # token at the TOP LEVEL (not nested under `user`), because no user is # resolved yet when the trigger fires. Capture it here -- with the same # "set it aside, keep it out of as_json / the log" treatment as the # nested form -- so #user_client / #user_agent can act as the caller. # It is intentionally NOT one of ATTRIBUTES. if @session_token.nil? top_token = hash[:session_token].to_s.strip @session_token = top_token unless top_token.empty? end # Webhook trigger payloads (beforeSave/afterSave/etc.) are delivered by # Parse Server and, when a webhook key is configured (the default; see # Parse::Webhooks.allow_unauthenticated for the opt-out used in tests / # local dev), authenticated by it -- so they are treated as trusted, # server-authoritative state. A handler is meant to receive the full # object -- createdAt/updatedAt, ACL, internal fields and all. The only # thing stripped here is genuine credential material a handler never # legitimately needs to read inline (live session tokens -- captured # above for opt-in user-scoped clients first -- and offline-crackable # password hashes); see WEBHOOK_TRIGGER_CREDENTIAL_KEYS. Protection # against *persisting* forged privileged fields lives on the write path # (changes_payload emits only declared, dirty-tracked properties), not on # this read path. if hash[:user].present? # Trusted hydration via .build (not .new) so server-sent timestamps and # data fields remain readable; credentials are removed first. Note # Parse::User applies its own protections, so `payload.user.auth_data` # is not exposed here. The built object is pristine, so a handler that # saves payload.user transmits nothing (no dirty changes) and cannot # persist forgeries. @user = Parse::User.build(self.class.scrub_credentials(hash[:user])) end @installation_id = hash[:installation_id] @params = hash[:params] @params = @params.with_indifferent_access if @params.is_a?(Hash) @function_name = hash[:function_name] @trigger_name = hash[:trigger_name] # Resolve the model class once so :vector columns can be stripped from # every object-shaped payload (see scrub_vector_columns). Credentials # are scrubbed first, then vectors. The route-derived @webhook_class is # authoritative and preferred — it is the only class source for # afterFind (whose body carries no className anywhere); for save/delete # it equals the body's className. Falls back to the object/original # className for older callers that don't supply a route class. vec_klass = self.class.resolve_klass_by_name(@webhook_class) || self.class.resolve_vector_klass(hash[:object], hash[:original]) @object = self.class.scrub_vector_columns(self.class.scrub_credentials(hash[:object]), vec_klass) @original = self.class.scrub_vector_columns(self.class.scrub_credentials(hash[:original]), vec_klass) @update = self.class.scrub_vector_columns(self.class.scrub_credentials(hash[:update]), vec_klass) || {} # Added for beforeFind and afterFind triggers. afterFind objects are all # of one class but carry no className of their own, so the route-derived # vec_klass is the only way to strip their :vector columns. @query = hash[:query] # LiveQuery connection metadata. `event` is the afterEvent event type # (create/enter/update/leave/delete) or "connect" for beforeConnect; # `clients`/`subscriptions` are connection-global counts. All nil for # the object / auth triggers. These are plain scalars (no credential # material), so they pass through unscrubbed. @event = hash[:event] @clients = hash[:clients] @subscriptions = hash[:subscriptions] @objects = Array(hash[:objects]).map do |o| self.class.scrub_vector_columns(self.class.scrub_credentials(o), vec_klass) end @log = hash[:log] # Caller-supplied context object threaded via X-Parse-Cloud-Context. # This is caller metadata (not a credential), so it passes through # without scrubbing — mirroring the treatment of @query and @log. @context = hash[:context] # Blocks registered by a handler via #after_response / #defer, to run # after the webhook response has been sent (drained by the Rack app). @deferred_callbacks = [] end |
Instance Attribute Details
#clients ⇒ Integer?
Connection-global metadata sent on the LiveQuery +beforeConnect+ / +afterEvent+ triggers: the number of currently-connected LiveQuery clients. +nil+ for non-LiveQuery triggers.
85 |
# File 'lib/parse/webhooks/payload.rb', line 85 attr_accessor :event, :clients, :subscriptions |
#context ⇒ Hash?
The caller-supplied context object threaded from the originating REST write or cloud-function call via the +X-Parse-Cloud-Context+ header. Parse Server includes this as a top-level +context+ key in trigger payloads (beforeSave/afterSave/etc.). Returns a Hash when present, or +nil+ when the originating request carried no context.
93 94 95 |
# File 'lib/parse/webhooks/payload.rb', line 93 def context @context end |
#event ⇒ String?
The LiveQuery event type for an +afterEvent+ trigger -- one of +"create"+, +"enter"+, +"update"+, +"leave"+, or +"delete"+ -- or +"connect"+ for a +beforeConnect+ trigger. +nil+ for every non- LiveQuery trigger. See #after_event? / #before_connect?.
85 86 87 |
# File 'lib/parse/webhooks/payload.rb', line 85 def event @event end |
#function_name ⇒ String Also known as: functionName
Returns the name of the function.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#installation_id ⇒ String Also known as: installationId
Returns The identifier of the device that submitted the request.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#log ⇒ Object
The query request in a beforeFind trigger. Available in Parse Server 2.3.1 or later. @return [Parse::Query] The set of matching objects in an afterFind trigger. Available in Parse Server 2.3.1 or later. @return [Parse::Object] Logging information if available. Available in Parse Server 2.3.1 or later. @return [Hash] the set of matching objects in an afterFind trigger.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#master ⇒ Boolean
Returns whether the master key was used for this request.
66 67 68 |
# File 'lib/parse/webhooks/payload.rb', line 66 def master @master end |
#object ⇒ Hash
In a beforeSave, this attribute is the final object that will be persisted.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#objects ⇒ Object
The query request in a beforeFind trigger. Available in Parse Server 2.3.1 or later. @return [Parse::Query] The set of matching objects in an afterFind trigger. Available in Parse Server 2.3.1 or later. @return [Parse::Object] Logging information if available. Available in Parse Server 2.3.1 or later. @return [Hash] the set of matching objects in an afterFind trigger.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#original ⇒ Hash
In a beforeSave, for previously saved objects, this attribute is the Parse::Object that was previously in the persistent store.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#params ⇒ Hash
Returns The list of function arguments submitted for a function request.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#query ⇒ Object
The query request in a beforeFind trigger. Available in Parse Server 2.3.1 or later. @return [Parse::Query] The set of matching objects in an afterFind trigger. Available in Parse Server 2.3.1 or later. @return [Parse::Object] Logging information if available. Available in Parse Server 2.3.1 or later. @return [Hash] the set of matching objects in an afterFind trigger.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#raw ⇒ Hash
Returns the raw payload from Parse server.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#session_token ⇒ Object (readonly)
Returns the value of attribute session_token.
105 106 107 |
# File 'lib/parse/webhooks/payload.rb', line 105 def session_token @session_token end |
#subscriptions ⇒ Integer?
Connection-global metadata sent on the LiveQuery +beforeConnect+ / +afterEvent+ triggers: the number of active subscriptions. +nil+ for non-LiveQuery triggers.
85 |
# File 'lib/parse/webhooks/payload.rb', line 85 attr_accessor :event, :clients, :subscriptions |
#trigger_name ⇒ String Also known as: triggerName
Returns the name of the trigger (ex. beforeSave, afterSave, etc.).
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#update ⇒ Hash
Returns the update payload in the request.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
#user ⇒ Parse::User
Returns the user who performed this request or action.
66 |
# File 'lib/parse/webhooks/payload.rb', line 66 attr_accessor :master, :user, :installation_id, :params, :function_name, :object, :trigger_name |
Instance Method Details
#after_delete? ⇒ Boolean
true if this is a afterDelete webhook trigger request.
449 450 451 |
# File 'lib/parse/webhooks/payload.rb', line 449 def after_delete? trigger? && @trigger_name.to_sym == :afterDelete end |
#after_event? ⇒ Boolean
true if this is a LiveQuery afterEvent webhook trigger request. The event type (create/enter/update/leave/delete) is in #event.
507 508 509 |
# File 'lib/parse/webhooks/payload.rb', line 507 def after_event? trigger? && @trigger_name.to_sym == :afterEvent end |
#after_find? ⇒ Boolean
true if this is a afterFind webhook trigger request.
459 460 461 |
# File 'lib/parse/webhooks/payload.rb', line 459 def after_find? trigger? && @trigger_name.to_sym == :afterFind end |
#after_login? ⇒ Boolean
true if this is a afterLogin webhook trigger request.
475 476 477 |
# File 'lib/parse/webhooks/payload.rb', line 475 def after_login? trigger? && @trigger_name.to_sym == :afterLogin end |
#after_logout? ⇒ Boolean
true if this is a afterLogout webhook trigger request. The logged-out session is carried as #object / #parse_object (a +_Session+).
481 482 483 |
# File 'lib/parse/webhooks/payload.rb', line 481 def after_logout? trigger? && @trigger_name.to_sym == :afterLogout end |
#after_response { ... } ⇒ Boolean Also known as: defer
Register a block to run after this webhook's response has been sent to Parse Server, off the client's critical path. Use it to do work that should not add latency to the save/function the client is waiting on — search indexing, cache warming, fan-out notifications.
The handler still returns its value synchronously (the response Parse
Server acts on); the deferred block runs afterward. When the SDK is
mounted under a server that supports rack.after_reply (Puma, Unicorn)
the block runs once the response is flushed to the socket, on the same
worker thread; otherwise it runs in a detached thread. Each block is
isolated, so one raising neither affects the response nor the others.
Parse::Webhooks.route :after_save, :Post do post = parse_object after_response { SearchIndex.reindex(post.id) } post end
self inside the block is this payload (it closes over the handler's
scope), so parse_object, params, etc. remain available. Note the
block runs in-process and does not survive a worker restart — for work
that must happen, hand it to a durable job queue instead. Deferred
callbacks fire only when the payload is processed through the mounted
Parse::Webhooks Rack app.
715 716 717 718 719 720 |
# File 'lib/parse/webhooks/payload.rb', line 715 def after_response(&block) return false unless block_given? @deferred_callbacks ||= [] @deferred_callbacks << block true end |
#after_save? ⇒ Boolean
true if this is a afterSave webhook trigger request.
439 440 441 |
# File 'lib/parse/webhooks/payload.rb', line 439 def after_save? trigger? && @trigger_name.to_sym == :afterSave end |
#after_trigger? ⇒ Boolean
true if this is a afterSave or afterDelete webhook trigger request.
429 430 431 |
# File 'lib/parse/webhooks/payload.rb', line 429 def after_trigger? after_save? || after_delete? || after_find? end |
#attributes ⇒ ATTRIBUTES
319 320 321 |
# File 'lib/parse/webhooks/payload.rb', line 319 def attributes ATTRIBUTES end |
#auth_trigger? ⇒ Boolean
true if this is one of the authentication-side triggers (beforeLogin / afterLogin / afterLogout / beforePasswordResetRequest). These carry a +_User+ / +_Session+ as #object but are NOT object save/delete triggers: no ActiveModel save/create/destroy callbacks run for them, and Parse Server ignores the response body (the only way to affect a +before*+ one is to deny it -- see the webhook router).
517 518 519 |
# File 'lib/parse/webhooks/payload.rb', line 517 def auth_trigger? before_login? || after_login? || after_logout? || before_password_reset_request? end |
#before_connect? ⇒ Boolean
true if this is a LiveQuery beforeConnect webhook trigger request. Connection-global: carries no #object; the className is the +@Connect+ sentinel and the caller's token (if any) is in #session_token.
494 495 496 |
# File 'lib/parse/webhooks/payload.rb', line 494 def before_connect? trigger? && @trigger_name.to_sym == :beforeConnect end |
#before_delete? ⇒ Boolean
true if this is a beforeDelete webhook trigger request.
444 445 446 |
# File 'lib/parse/webhooks/payload.rb', line 444 def before_delete? trigger? && @trigger_name.to_sym == :beforeDelete end |
#before_find? ⇒ Boolean
true if this is a beforeFind webhook trigger request.
454 455 456 |
# File 'lib/parse/webhooks/payload.rb', line 454 def before_find? trigger? && @trigger_name.to_sym == :beforeFind end |
#before_login? ⇒ Boolean
true if this is a beforeLogin webhook trigger request.
NOTE: a +beforeLogin+ payload carries the user being authenticated as #object / #parse_object (a +_User+), NOT as #user -- the caller is not yet authenticated when the trigger fires, so #user is +nil+. (By +afterLogin+ both are populated and equal.) Reach for #parse_object to inspect the logging-in user during +beforeLogin+.
470 471 472 |
# File 'lib/parse/webhooks/payload.rb', line 470 def before_login? trigger? && @trigger_name.to_sym == :beforeLogin end |
#before_password_reset_request? ⇒ Boolean
true if this is a beforePasswordResetRequest webhook trigger request. The target user is carried as #object / #parse_object (a +_User+).
487 488 489 |
# File 'lib/parse/webhooks/payload.rb', line 487 def before_password_reset_request? trigger? && @trigger_name.to_sym == :beforePasswordResetRequest end |
#before_save? ⇒ Boolean
true if this is a beforeSave webhook trigger request.
434 435 436 |
# File 'lib/parse/webhooks/payload.rb', line 434 def before_save? trigger? && @trigger_name.to_sym == :beforeSave end |
#before_subscribe? ⇒ Boolean
true if this is a LiveQuery beforeSubscribe webhook trigger request. Shaped like beforeFind: carries a #query (see #parse_query) and the className comes from the request path, not the body.
501 502 503 |
# File 'lib/parse/webhooks/payload.rb', line 501 def before_subscribe? trigger? && @trigger_name.to_sym == :beforeSubscribe end |
#before_trigger? ⇒ Boolean
true if this is a beforeSave or beforeDelete webhook trigger request.
424 425 426 |
# File 'lib/parse/webhooks/payload.rb', line 424 def before_trigger? before_save? || before_delete? || before_find? end |
#client_initiated? ⇒ Boolean
Returns true if this webhook was triggered by a client request (JavaScript, iOS, Android, etc.) This is the inverse of ruby_initiated? and is useful for callback logic that should only run for client-initiated operations.
772 773 774 |
# File 'lib/parse/webhooks/payload.rb', line 772 def client_initiated? !ruby_initiated? end |
#error!(msg = "") ⇒ Parse::Webhooks::ResponseError
This method will intentionally raise a ResponseError with a specific message. When used inside of a registered cloud code webhook function or trigger, will halt processing and return the proper error response code back to the Parse server.
684 685 686 |
# File 'lib/parse/webhooks/payload.rb', line 684 def error!(msg = "") raise Parse::Webhooks::ResponseError, msg end |
#function? ⇒ Boolean
true if this is a webhook function request.
349 350 351 |
# File 'lib/parse/webhooks/payload.rb', line 349 def function? @function_name.present? end |
#inspect ⇒ Object
Redacted inspection. The default Ruby #inspect would dump every ivar,
including the captured @session_token and the pre-scrub @raw hash
(which still holds the caller's sessionToken and any password hashes).
That is exactly the surface an error reporter or a stray p payload
hits, so show only non-sensitive routing fields and a boolean for the
token's presence. Use #as_json / the individual accessors for the
(already credential-scrubbed) object data.
330 331 332 333 334 335 |
# File 'lib/parse/webhooks/payload.rb', line 330 def inspect "#<#{self.class.name} trigger=#{@trigger_name.inspect} " \ "function=#{@function_name.inspect} class=#{parse_class.inspect} " \ "id=#{parse_id.inspect} master=#{@master ? true : false} " \ "session_token=#{@session_token ? "[FILTERED]" : "nil"}>" end |
#live_query_trigger? ⇒ Boolean
true if this is one of the LiveQuery triggers (beforeConnect / beforeSubscribe / afterEvent). Parse Server delivers these over an HTTP webhook only in a co-located single-process LiveQuery setup; +beforeConnect+ in particular carries a live client and is effectively in-process-only. See the webhooks guide.
526 527 528 |
# File 'lib/parse/webhooks/payload.rb', line 526 def live_query_trigger? before_connect? || before_subscribe? || after_event? end |
#master? ⇒ Boolean
true if the master key was used for this request.
354 355 356 |
# File 'lib/parse/webhooks/payload.rb', line 354 def master? @master.present? end |
#object? ⇒ Boolean
true if this request is a trigger that contains an object.
531 532 533 |
# File 'lib/parse/webhooks/payload.rb', line 531 def object? trigger? && @object.present? end |
#original_parse_object ⇒ Parse::Object
Returns a Parse::Object from the original object.
536 537 538 539 540 541 542 |
# File 'lib/parse/webhooks/payload.rb', line 536 def original_parse_object return nil unless @original.is_a?(Hash) # Always pass the trigger's expected class explicitly so the # className inside the payload cannot redirect this hydration to a # different class. Parse::Object.build(@original, parse_class) end |
#parse_class ⇒ String
Returns the name of the Parse class for this request.
404 405 406 407 408 |
# File 'lib/parse/webhooks/payload.rb', line 404 def parse_class return @webhook_class if @webhook_class.present? return nil unless @object.present? @object[Parse::Model::KEY_CLASS_NAME] || @object[:className] end |
#parse_id ⇒ String Also known as: objectId
Returns the objectId in this request.
411 412 413 414 |
# File 'lib/parse/webhooks/payload.rb', line 411 def parse_id return nil unless @object.present? @object[Parse::Model::OBJECT_ID] || @object[:objectId] end |
#parse_object(pristine = false) ⇒ Parse::Object
This method returns a Parse::Object by combining the original object, if was provided, with the final object. This will return a dirty tracked Parse::Object subclass, that will have information on which fields have changed between the previous state in the persistent store and the one about to be saved.
550 551 552 553 554 555 556 557 558 559 560 |
# File 'lib/parse/webhooks/payload.rb', line 550 def parse_object(pristine = false) return nil unless object? return Parse::Object.build(@object, parse_class) if pristine # Memoize so pre-block guard application and the user webhook handler # observe the same instance. Otherwise field_guards applied on the # framework's pre-built object would be invisible to the block's # later parse_object call (which would construct a fresh dirty-tracked # object from @object/@original). return @parse_object if defined?(@parse_object) && !@parse_object.nil? @parse_object = build_parse_object end |
#parse_query ⇒ Parse::Query
Returns the Parse query for a beforeFind trigger.
732 733 734 735 |
# File 'lib/parse/webhooks/payload.rb', line 732 def parse_query return nil unless parse_class.present? && @query.is_a?(Hash) Parse::Query.new parse_class, @query end |
#ruby_initiated? ⇒ Boolean
Returns true if this webhook was triggered by a Ruby Parse Stack request. This is determined by checking for the 'RB' prefix in the request ID header. This flag is useful for preventing callback loops and implementing intelligent callback handling based on the request origin.
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 |
# File 'lib/parse/webhooks/payload.rb', line 742 def ruby_initiated? @ruby_initiated ||= begin request_id = nil if @raw.respond_to?(:[]) # Check for headers at the top level first request_id = @raw["x-parse-request-id"] || @raw["X-Parse-Request-Id"] || @raw[:x_parse_request_id] || @raw[:'X-Parse-Request-Id'] # If not found at top level, check nested headers if request_id.nil? headers_sym = @raw[:headers] if @raw[:headers].is_a?(Hash) headers_str = @raw["headers"] if @raw["headers"].is_a?(Hash) if headers_sym request_id = headers_sym["x-parse-request-id"] || headers_sym["X-Parse-Request-Id"] elsif headers_str request_id = headers_str["x-parse-request-id"] || headers_str["X-Parse-Request-Id"] end end end request_id&.start_with?("_RB_") || false end end |
#session_token? ⇒ Boolean
true if this payload carried a caller session token -- i.e. the originating request was made by a logged-in user rather than the master key, so #user_client / #user_agent can act as that user.
362 363 364 |
# File 'lib/parse/webhooks/payload.rb', line 362 def session_token? !@session_token.nil? end |
#trigger? ⇒ Boolean
true if this is a webhook trigger request.
419 420 421 |
# File 'lib/parse/webhooks/payload.rb', line 419 def trigger? @trigger_name.present? end |
#user_agent(**opts) ⇒ Parse::Agent?
An opt-in, non-master Agent scoped to the webhook caller's session token. Because its client has no master key and it is built with a non-empty +session_token:+, the agent runs in CLIENT MODE: every tool/query routes through a path Parse Server (or the SDK's own ACL/CLP enforcement layer) authorizes as the calling user, with no master-key fallback to silently bypass row-level security. This is the handle to use when a handler should read or act strictly within the caller's permissions. Additional agent options (e.g. +permissions: :readwrite+) may be passed through.
392 393 394 395 396 397 398 399 400 401 |
# File 'lib/parse/webhooks/payload.rb', line 392 def user_agent(**opts) return nil if @session_token.nil? require_relative "../agent" unless defined?(Parse::Agent) # Strip the two identity kwargs from the passthrough: a Ruby double-splat # that repeats an explicit keyword WINS, so user_agent(client: master) # or user_agent(session_token: other) would otherwise silently defeat the # whole point (scoping to the caller). The scoping is non-negotiable here. opts = opts.except(:session_token, :client) Parse::Agent.new(session_token: @session_token, client: user_client, **opts) end |
#user_client ⇒ Parse::Client?
An opt-in, user-scoped Client for acting on the server as the
webhook's calling user. It mirrors the default client's connection
settings (+server_url+, +application_id+, +api_key+) but carries NO
master key and BINDS the caller's #session_token, so every request it
makes -- with no further ceremony -- is authorized by Parse Server as
that user: ACL, CLP and +protectedFields+ are all enforced. (A
Parse.with_session block still overrides the bound token if you need
to act as someone else within a call.) Memoized per payload, since each
webhook delivery carries a distinct token.
376 377 378 379 |
# File 'lib/parse/webhooks/payload.rb', line 376 def user_client return nil if @session_token.nil? @user_client ||= Parse::Client.client.become(@session_token) end |
#wlog(s) ⇒ Object
Method to print to standard that utilizes the an internal id to make it easier to trace incoming requests.
339 340 341 342 343 344 345 346 |
# File 'lib/parse/webhooks/payload.rb', line 339 def wlog(s) # generates a unique random number in order to be used in logging. This # is useful when debugging issues in production where one server instance # may be running multiple threads and you want to trace the incoming call. @rid ||= rand(999).to_s.rjust(3) puts "[> #{@rid}] #{s}" @rid end |