Module: Webhookdb::Replicator::IntercomV1Mixin

Included in:
IntercomContactV1, IntercomConversationV1
Defined in:
lib/webhookdb/replicator/intercom_v1_mixin.rb

Constant Summary collapse

QUESTIONABLE_TIMESTAMP =

Timestamps can be unix timestamps when listing a resource, or strings in other cases, like webhooks. This may have to do with API versions. Handle both.

Webhookdb::Replicator::Column::IsomorphicProc.new(
  ruby: lambda do |i, **_|
    return nil if i.nil?
    return Time.at(i)
  rescue TypeError
    return Time.parse(i)
  end,
  sql: lambda do |*|
    # We would have to check the type of the data, which is a pain, so don't worry about this for now.
    raise NotImplementedError
  end,
)

Instance Method Summary collapse

Instance Method Details

#_fetch_backfill_page(pagination_token, **_kwargs) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 77

def _fetch_backfill_page(pagination_token, **_kwargs)
  unless self.auth_credentials?
    raise Webhookdb::Replicator::CredentialsMissing,
          "This integration requires that the Intercom Auth integration has a valid Auth Token"
  end

  query = {per_page: Webhookdb::Intercom.page_size}
  # Intercom started 500ing with this set to empty.
  query[:starting_after] = pagination_token if pagination_token
  begin
    response = Webhookdb::Http.get(
      self._mixin_backfill_url,
      query:,
      headers: self.intercom_auth_headers,
      logger: self.logger,
      timeout: Webhookdb::Intercom.http_timeout,
    )
  rescue Webhookdb::Http::Error => e
    is_token_suspended = e.status == 401 &&
      e.response["errors"].present? &&
      e.response["errors"].any? { |er| er["code"] == "token_suspended" }
    if is_token_suspended
      root_sint = self.find_auth_integration
      message = "Organization has closed their Intercom workspace and this integration should be deleted. " \
                "From a console, run: " \
                "Webhookdb::ServiceIntegration[#{root_sint.id}].destroy_self_and_all_dependents"
      Webhookdb::DeveloperAlert.new(
        subsystem: "Intercom Workspace Closed Error",
        emoji: ":hook:",
        fallback: message,
        fields: [
          {title: "Organization", value: root_sint.organization.name, short: true},
          {title: "Integration ID", value: root_sint.id.to_s, short: true},
          {title: "Instructions", value: message},
        ],
      ).emit
      # Noop here since there's nothing to do, the developer alert takes care of notifying
      # so no need to error or log.
      return [], nil
    end
    #  We are looking to catch the "api plan restricted" error. This is always a 403 and every
    # 403 will be an "api plan restricted" error according to the API documentation. Because we
    # specify the API version in our headers we can expect that this won't change.
    raise e unless e.status == 403
    self.logger.warn("intercom_api_restricted", intercom_error: e.body)
    # We should basically noop here, i.e. pretend that the page is empty, so that we don't trigger
    # a TypeError in the backfiller.
    return [], nil
  end
  data = response.parsed_response.fetch("data", [])
  starting_after = response.parsed_response.dig("pages", "next", "starting_after")
  return data, starting_after
end

#_mixin_backfill_urlObject

Raises:

  • (NotImplementedError)


75
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 75

def _mixin_backfill_url = raise NotImplementedError

#_resource_and_event(request) ⇒ Object



40
41
42
43
44
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 40

def _resource_and_event(request)
  body = request.body
  return body.fetch("data").fetch("item"), body if body.fetch("type") == "notification_event"
  return body, nil
end

#_timestamp_column_nameObject



50
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 50

def _timestamp_column_name = :updated_at

#_update_where_exprObject



46
47
48
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 46

def _update_where_expr
  return self.qualified_table_sequel_identifier[:updated_at] < Sequel[:excluded][:updated_at]
end

#_webhook_response(request) ⇒ Object



52
53
54
55
56
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 52

def _webhook_response(request)
  # Intercom webhooks are done through a centralized oauth replicator,
  # so the secret is for the app, not the individual replicator.
  return Webhookdb::Intercom.webhook_response(request, Webhookdb::Intercom.client_secret)
end

#auth_credentials?Boolean

Returns:

  • (Boolean)


35
36
37
38
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 35

def auth_credentials?
  auth = self.find_auth_integration
  return auth.backfill_key.present?
end

#calculate_backfill_state_machineWebhookdb::Replicator::StateMachineStep



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 59

def calculate_backfill_state_machine
  # can inherit credentials from the auth dependency
  if (step = self.calculate_dependency_state_machine_step(dependency_help: ""))
    return step
  end
  step = Webhookdb::Replicator::StateMachineStep.new
  step.output = %(We will start replicating #{self.resource_name_singular} information into your WebhookDB database.

#{self._query_help_output(prefix: "Once data is available, you can query #{self.resource_name_plural}.")})
  return step.completed
end

#find_auth_integrationObject

Quick note on these Intercom integrations: although we will technically be bringing in information from webhooks, all webhooks for the WebhookDB app will use a single endpoint and we use the WebhookDB app’s Client Secret for webhook verification, which means that webhooks actually don’t require any setup on the integration level. Thus, ‘supports_webhooks` is false.



24
25
26
27
28
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 24

def find_auth_integration
  return @find_auth_integration ||= Webhookdb::Replicator.find_at_root!(
    self.service_integration, service_name: "intercom_marketplace_root_v1",
  )
end

#intercom_auth_headersObject



30
31
32
33
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 30

def intercom_auth_headers
  root_sint = self.find_auth_integration
  return Webhookdb::Intercom.auth_headers(root_sint.backfill_key)
end

#on_dependency_webhook_upsert(_replicator, _payload) ⇒ Object



71
72
73
# File 'lib/webhookdb/replicator/intercom_v1_mixin.rb', line 71

def on_dependency_webhook_upsert(_replicator, _payload, *)
  return
end