Class: Spree::WebhookEndpoint

Inherits:
Object
  • Object
show all
Includes:
SingleStoreResource
Defined in:
app/models/spree/webhook_endpoint.rb

Constant Summary collapse

AUTO_DISABLE_THRESHOLD =

Number of consecutive failed deliveries before auto-disabling

15

Instance Method Summary collapse

Instance Method Details

#auto_disabled?Boolean

Check if the endpoint was auto-disabled

Returns:

  • (Boolean)


116
117
118
# File 'app/models/spree/webhook_endpoint.rb', line 116

def auto_disabled?
  disabled_at.present?
end

#check_auto_disable!Object

Check if auto-disable threshold has been reached and disable if so.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'app/models/spree/webhook_endpoint.rb', line 122

def check_auto_disable!
  return if auto_disabled?

  consecutive_failures = webhook_deliveries
    .where(success: false)
    .where.not(delivered_at: nil)
    .order(delivered_at: :desc)
    .limit(AUTO_DISABLE_THRESHOLD)

  return if consecutive_failures.count < AUTO_DISABLE_THRESHOLD

  # Verify they're all failures (no successes interspersed)
  last_success = webhook_deliveries.successful.order(delivered_at: :desc).pick(:delivered_at)
  oldest_failure = consecutive_failures.last&.delivered_at

  if last_success.nil? || (oldest_failure && oldest_failure > last_success)
    disable!
  end
end

#disable!(reason: 'Automatically disabled after repeated delivery failures', notify: true) ⇒ Object

Disable this endpoint due to repeated failures. Sends a notification email to the store staff.

Parameters:

  • reason (String) (defaults to: 'Automatically disabled after repeated delivery failures')
  • notify (Boolean) (defaults to: true)

    whether to send an email notification (default: true)



103
104
105
106
# File 'app/models/spree/webhook_endpoint.rb', line 103

def disable!(reason: 'Automatically disabled after repeated delivery failures', notify: true)
  update!(active: false, disabled_reason: reason, disabled_at: Time.current)
  Spree::WebhookMailer.endpoint_disabled(self).deliver_later if notify
end

#enable!Object

Re-enable a previously disabled endpoint.



109
110
111
# File 'app/models/spree/webhook_endpoint.rb', line 109

def enable!
  update!(active: true, disabled_reason: nil, disabled_at: nil)
end

#secret_key_for_responseString?

Returns the plaintext ‘secret_key` only on the create response.

‘@reveal_secret_in_response` is set by the `after_create` callback above — a per-instance flag, not derived from `previous_changes`, so a reload or any subsequent save can’t accidentally re-expose the secret.

Returns:

  • (String, nil)


45
46
47
# File 'app/models/spree/webhook_endpoint.rb', line 45

def secret_key_for_response
  @reveal_secret_in_response ? secret_key : nil
end

#send_test!Spree::WebhookDelivery

Send a test/ping webhook to verify the endpoint is reachable. Creates a delivery record and queues it for delivery.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'app/models/spree/webhook_endpoint.rb', line 82

def send_test!
  delivery = webhook_deliveries.create!(
    event_name: 'webhook.test',
    payload: {
      id: SecureRandom.uuid,
      name: 'webhook.test',
      created_at: Time.current.iso8601,
      data: { message: 'This is a test webhook from Spree.' },
      metadata: { spree_version: Spree.version }
    }
  )

  delivery.queue_for_delivery!
  delivery
end

#subscribed_eventsArray<String>

Returns all events this endpoint is subscribed to

Returns:

  • (Array<String>)


72
73
74
75
76
# File 'app/models/spree/webhook_endpoint.rb', line 72

def subscribed_events
  return ['*'] if subscriptions.blank?

  subscriptions
end

#subscribed_to?(event_name) ⇒ Boolean

Check if this endpoint is subscribed to a specific event

Parameters:

  • event_name (String)

    the event name to check

Returns:

  • (Boolean)


56
57
58
59
60
61
62
63
64
65
66
67
# File 'app/models/spree/webhook_endpoint.rb', line 56

def subscribed_to?(event_name)
  return true if subscriptions.blank? || subscriptions.include?('*')

  subscriptions.any? do |subscription|
    if subscription.include?('*')
      pattern = Regexp.escape(subscription).gsub('\*', '.*')
      event_name.match?(Regexp.new("^#{pattern}$"))
    else
      subscription == event_name
    end
  end
end