class ForestLiana::Bootstrapper

Constants

SCHEMA_FILENAME

Public Class Methods

new() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 8
def initialize
  @integration_stripe_valid = false
  @integration_intercom_valid = false

  if ForestLiana.secret_key && ForestLiana.auth_key
    FOREST_LOGGER.warn "DEPRECATION WARNING: The use of " \
      "ForestLiana.secret_key and ForestLiana.auth_key " \
      "(config/initializers/forest_liana.rb) is deprecated. Please use " \
      "ForestLiana.env_secret and ForestLiana.auth_secret instead."
    ForestLiana.env_secret = ForestLiana.secret_key
    ForestLiana.auth_secret = ForestLiana.auth_key
  end

  unless Rails.application.config.action_controller.perform_caching || Rails.env.test? || ForestLiana.forest_client_id
    FOREST_LOGGER.error "You need to enable caching on your environment to use Forest Admin.\n" \
      "For a development environment, run: `rails dev:cache`\n" \
      "Or setup a static forest_client_id by following this part of the documentation:\n" \
      "https://docs.forestadmin.com/documentation/how-tos/maintain/upgrade-notes-rails/upgrade-to-v6#setup-a-static-clientid"
  end

  fetch_models
  check_integrations_setup
  namespace_duplicated_models
  create_factories

  generate_apimap if ForestLiana.env_secret
end

Private Class Methods

find_serializer_class_name(record, options) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 145
def self.find_serializer_class_name(record, options)
  if record.respond_to?(:jsonapi_serializer_class_name)
    record.jsonapi_serializer_class_name.to_s
  else
    ForestLiana::SerializerFactory.get_serializer_name(record.class)
  end
end

Public Instance Methods

display_apimap() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 40
def display_apimap
  if ForestLiana.env_secret
    puts " = Current Forest Apimap:\n#{JSON.pretty_generate(get_apimap_serialized)}"
  end
end
synchronize(with_feedback=false) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 36
def synchronize(with_feedback=false)
  send_apimap(with_feedback) if ForestLiana.env_secret
end

Private Instance Methods

analyze_model?(model) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 103
def analyze_model?(model)
  model && model.table_exists? && !SchemaUtils.habtm?(model) &&
    SchemaUtils.model_included?(model)
end
cast_to_array(value) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 132
def cast_to_array value
  value.is_a?(String) ? [value] : value
end
check_integrations_setup() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 155
def check_integrations_setup
  if stripe_integration?
    if stripe_integration_valid? || stripe_integration_deprecated?
      ForestLiana.integrations[:stripe][:mapping] =
        cast_to_array(ForestLiana.integrations[:stripe][:mapping])
      @integration_stripe_valid = true
    else
      FOREST_LOGGER.error 'Cannot setup properly your Stripe integration.' \
        'Please go to https://doc.forestadmin.com for more information.'
    end
  end

  if intercom_integration?
    if intercom_integration_valid?
      ForestLiana.integrations[:intercom][:mapping] =
        cast_to_array(ForestLiana.integrations[:intercom][:mapping])
      @integration_intercom_valid = true
    else
      FOREST_LOGGER.error 'Cannot setup properly your Intercom integration. ' \
        'Please go to https://doc.forestadmin.com for more information.'
    end
  end

  if mixpanel_integration?
    if mixpanel_integration_valid?
      ForestLiana.integrations[:mixpanel][:mapping] =
        cast_to_array(ForestLiana.integrations[:mixpanel][:mapping])
      @integration_mixpanel_valid = true
    else
      FOREST_LOGGER.error 'Cannot setup properly your Mixpanel integration. ' \
        'Please go to https://doc.forestadmin.com for more information.'
    end
  end
end
create_apimap() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 217
def create_apimap
  setup_forest_liana_meta

  ForestLiana.models.map do |model|
    if analyze_model?(model)
      SchemaAdapter.new(model).perform
    end
  end

  if @integration_stripe_valid
    ForestLiana.integrations[:stripe][:mapping].each do |collection|
      setup_stripe_integration collection
    end
  end

  if @integration_intercom_valid
    ForestLiana.integrations[:intercom][:mapping].each do |collection_name|
      setup_intercom_integration collection_name
    end
  end

  if @integration_mixpanel_valid
    ForestLiana.integrations[:mixpanel][:mapping].each do |collection_name|
      setup_mixpanel_integration collection_name
    end
  end
end
create_factories() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 136
def create_factories
  ForestLiana.models.uniq.map do |model|
    ForestLiana::SerializerFactory.new.serializer_for(model)
    ForestLiana::ControllerFactory.new.controller_for(model)
  end

  # Monkey patch the find_serializer_class_name method to specify the
  # good serializer to use.
  ::ForestAdmin::JSONAPI::Serializer.class_eval do
    def self.find_serializer_class_name(record, options)
      if record.respond_to?(:jsonapi_serializer_class_name)
        record.jsonapi_serializer_class_name.to_s
      else
        ForestLiana::SerializerFactory.get_serializer_name(record.class)
      end
    end
  end
end
database_type() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 660
def database_type
  begin
    connection = ActiveRecord::Base.connection
    if connection.try(:config)
      connection.config[:adapter]
    else
      connection.instance_values['config'][:adapter]
    end
  rescue
    'unknown'
  end
end
fetch_model(model) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 112
def fetch_model(model)
  begin
    if model.abstract_class?
      model.descendants.each { |submodel| fetch_model(submodel) }
    else
      if is_sti_parent_model?(model)
        model.descendants.each { |submodel_sti| fetch_model(submodel_sti) }
      end

      if analyze_model?(model)
        ForestLiana.models << model
      end
    end
  rescue => exception
    FOREST_REPORTER.report exception
    FOREST_LOGGER.error "Cannot fetch properly model #{model.name}:\n" \
      "#{exception}"
  end
end
fetch_models() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 108
def fetch_models
  ActiveRecord::Base.subclasses.each { |model| fetch_model(model) }
end
forest_url() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 656
def forest_url
  ENV['FOREST_URL'] || 'https://api.forestadmin.com'
end
format_and_validate_smart_actions() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 251
def format_and_validate_smart_actions
  ForestLiana.apimap.each do |collection|
    collection.actions.each do |action|
      if action.fields
        # NOTICE: Set a position to the Smart Actions fields.
        action.fields.each_with_index do |field, index|
          field[:position] = index
        end
      end
    end
  end
end
generate_action_hooks() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 56
def generate_action_hooks()
  @collections_sent.each do |collection|
    collection['actions'].each do |action|
      c = get_collection(collection['name'])
      a = get_action(c, action['name'])
      load = !a.hooks.nil? && a.hooks.key?(:load) && a.hooks[:load].is_a?(Proc)
      change = !a.hooks.nil? && a.hooks.key?(:change) && a.hooks[:change].is_a?(Hash) ? a.hooks[:change].keys : []
      action['hooks'] = {'load' => load, 'change' => change}
    end
  end
end
generate_apimap() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 68
def generate_apimap
  create_apimap
  require_lib_forest_liana
  format_and_validate_smart_actions

  if Rails.env.development?
    @collections_sent = ForestLiana.apimap.as_json
    @meta_sent = ForestLiana.meta
    generate_action_hooks
    SchemaFileUpdater.new(SCHEMA_FILENAME, @collections_sent, @meta_sent).perform()
  else
    if File.exists?(SCHEMA_FILENAME)
      begin
        content = JSON.parse(File.read(SCHEMA_FILENAME))
        @collections_sent = content['collections']
        @meta_sent = content['meta']
        generate_action_hooks
      rescue JSON::JSONError => error
        FOREST_REPORTER.report error
        FOREST_LOGGER.error "The content of .forestadmin-schema.json file is not a correct JSON."
        FOREST_LOGGER.error "The schema cannot be synchronized with Forest Admin servers."
      end
    else
      FOREST_LOGGER.error "The .forestadmin-schema.json file does not exist."
      FOREST_LOGGER.error "The schema cannot be synchronized with Forest Admin servers."
    end
  end
end
get_action(collection, action_name) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 52
def get_action(collection, action_name)
  collection.actions.find {|action| action.name == action_name}
end
get_apimap_serialized() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 264
def get_apimap_serialized
  serializer = ForestLiana::SchemaSerializer.new(@collections_sent, @meta_sent)
  apimap = serializer.serialize
  ForestLiana::ApimapSorter.new(apimap).perform
end
get_collection(collection_name) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 48
def get_collection(collection_name)
  ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
end
intercom_integration?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 385
def intercom_integration?
  ForestLiana.integrations
    .try(:[], :intercom)
    .present?
end
intercom_integration_valid?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 391
def intercom_integration_valid?
  integration = ForestLiana.integrations.try(:[], :intercom)
  integration.present? && integration.has_key?(:access_token) && integration.has_key?(:mapping)
end
is_sti_parent_model?(model) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 97
def is_sti_parent_model?(model)
  return false unless model.try(:table_exists?)

  model.inheritance_column && model.columns.find { |column| column.name == model.inheritance_column }
end
mixpanel_integration?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 644
def mixpanel_integration?
  ForestLiana.integrations
    .try(:[], :mixpanel)
    .present?
end
mixpanel_integration_valid?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 650
def mixpanel_integration_valid?
  integration = ForestLiana.integrations.try(:[], :mixpanel)
  integration.present? && integration.has_key?(:api_secret) &&
  integration.has_key?(:mapping)
end
namespace_duplicated_models() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 190
def namespace_duplicated_models
  ForestLiana.models
    .group_by { |model| model.table_name }
    .select { |table_name, models| models.length > 1 }
    .try(:each) do |table_name, models|
      models.each do |model|
        unless model.name.deconstantize.blank?
          ForestLiana.names_overriden[model] = model.name.gsub('::', '__')
        end
        # TODO: Remove once lianas prior to 2.0.0 are not supported anymore.
        ForestLiana.names_old_overriden[model] =
          "#{model.name.deconstantize.downcase}__#{model.table_name}"
      end
    end
end
require_lib_forest_liana() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 245
def require_lib_forest_liana
  Dir.glob(ForestLiana.config_dir).each do |file|
    load file
  end
end
send_apimap(with_feedback=false) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 270
def send_apimap(with_feedback=false)
  if ForestLiana.env_secret && ForestLiana.env_secret.length != 64
    FOREST_LOGGER.error "Your env_secret does not seem to be correct. " \
      "Can you check on Forest that you copied it properly in the " \
      "forest_liana initializer?"
  else
    apimap = get_apimap_serialized

    begin
      puts " = Sending Forest Apimap:\n#{JSON.pretty_generate(apimap)}" if with_feedback
      uri = URI.parse("#{forest_url}/forest/apimaps")
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = true if forest_url.start_with?('https')
      http.start do |client|
        request = Net::HTTP::Post.new(uri.path)
        request.body = apimap.to_json
        request['Content-Type'] = 'application/json'
        request['forest-secret-key'] = ForestLiana.env_secret
        response = client.request(request)

        if ['200', '202', '204', '400', '404', '503'].include? response.code
          unless response.body.blank?
            warning = JSON.parse(response.body)['warning']
          end

          if with_feedback
            if response.is_a?(Net::HTTPOK) || response.is_a?(Net::HTTPNoContent)
              puts " = Apimap Received - nothing changed"
            elsif response.is_a?(Net::HTTPAccepted)
              puts " = Apimap Received - update detected (currently updating the UI)"
            end
          end

          if response.is_a?(Net::HTTPNotFound) # NOTICE: HTTP 404 Error
            FOREST_LOGGER.error "Cannot find the project related to the " \
              "env_secret you configured. Can you check on Forest that " \
              "you copied it properly in the forest_liana initializer?"
          elsif response.is_a?(Net::HTTPBadRequest) # NOTICE: HTTP 400 Error
            FOREST_LOGGER.error "An error occured with the apimap sent " \
              "to Forest. Please contact support@forestadmin.com for " \
              "further investigations."
          elsif response.is_a?(Net::HTTPServiceUnavailable) # NOTICE: HTTP 503 Error
            FOREST_LOGGER.warn "Forest is in maintenance for a few " \
              "minutes. We are upgrading your experience in the " \
              "forest. We just need a few more minutes to get it right."
          elsif warning
            FOREST_LOGGER.warn warning
          end
        else
          FOREST_LOGGER.error "Forest seems to be down right now. Please " \
            "contact support@forestadmin.com for further investigations."
        end
      end
    rescue Errno::ECONNREFUSED, SocketError
      FOREST_LOGGER.warn "Cannot send the apimap to Forest. Are you online?"
    rescue
      FOREST_LOGGER.warn "Cannot send the apimap to Forest. Forest might " \
        "currently be in maintenance."
    end
  end
end
setup_forest_liana_meta() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 206
def setup_forest_liana_meta
  ForestLiana.meta = {
    liana: 'forest-rails',
    liana_version: ForestLiana::VERSION,
    stack: {
       database_type: database_type,
       orm_version: Gem.loaded_specs["activerecord"].version.version,
    }
  }
end
setup_intercom_integration(collection_name) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 332
def setup_intercom_integration(collection_name)
  model_name = ForestLiana.name_for(collection_name.constantize)
  # TODO: Remove once lianas prior to 2.0.0 are not supported anymore.
  model_name_old = ForestLiana.name_old_for(collection_name.constantize)

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_intercom_conversations",
    name_old: "#{model_name_old}_intercom_conversations",
    icon: 'intercom',
    integration: 'intercom',
    only_for_relationships: true,
    is_virtual: true,
    is_searchable: false,
    fields: [
      { field: :subject, type: 'String' },
      { field: :body, type: ['String'] },
      { field: :open, type: 'Boolean'},
      { field: :read, type: 'Boolean'},
      { field: :assignee, type: 'String' }
    ]
  })

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_intercom_attributes",
    name_old: "#{model_name_old}_intercom_attributes",
    icon: 'intercom',
    integration: 'intercom',
    only_for_relationships: true,
    is_virtual: true,
    is_searchable: false,
    fields: [
      { field: :created_at, type: 'Date', is_filterable: false },
      { field: :updated_at, type: 'Date', is_filterable: false },
      { field: :session_count, type: 'Number', is_filterable: false },
      { field: :last_seen_ip, type: 'String', is_filterable: false },
      { field: :signed_up_at, type: 'Date', is_filterable: false },
      { field: :country, type: 'String', is_filterable: false },
      { field: :city, type: 'String', is_filterable: false },
      { field: :browser, type: 'String', is_filterable: false },
      { field: :platform, type: 'String', is_filterable: false },
      { field: :companies, type: 'String', is_filterable: false },
      { field: :segments, type: 'String', is_filterable: false },
      { field: :tags, type: 'String', is_filterable: false },
      {
        field: :geoloc,
        type: 'String',
        widget: 'map',
        is_filterable: false
      }
    ]
  })
end
setup_mixpanel_integration(collection_name_and_field) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 603
def setup_mixpanel_integration(collection_name_and_field)
  collection_name = collection_name_and_field.split('.')[0]
  model_name = ForestLiana.name_for(collection_name.constantize)

  field_attributes = { is_filterable: false , is_virtual: true, is_sortable: false }

  fields = [
    { field: :id, type: 'String' },
    { field: :event, type: 'String' },
    { field: :date, type: 'Date' },
    { field: :city, type: 'String' },
    { field: :region, type: 'String' },
    { field: :country, type: 'String' },
    { field: :timezone, type: 'String' },
    { field: :os, type: 'String' },
    { field: :osVersion, type: 'String' },
    { field: :browser, type: 'String' },
    { field: :browserVersion, type: 'String' },
  ]

  fields = fields.map { |field| field.merge(field_attributes) }

  custom_properties = ForestLiana.integrations[:mixpanel][:custom_properties]
  custom_properties = custom_properties.map { |property|
    { field: property.to_sym, type: 'String' }.merge(field_attributes)
  }

  fields = fields.concat(custom_properties)

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_mixpanel_events",
    icon: 'mixpanel',
    integration: 'mixpanel',
    is_virtual: true,
    is_read_only: true,
    only_for_relationships: true,
    pagination_type: 'cursor',
    fields: fields
  })
end
setup_stripe_integration(collection_name_and_field) click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 396
def setup_stripe_integration(collection_name_and_field)
  collection_name = collection_name_and_field.split('.')[0]
  model_name = ForestLiana.name_for(collection_name.constantize)
  # TODO: Remove once lianas prior to 2.0.0 are not supported anymore.
  model_name_old = ForestLiana.name_old_for(collection_name.constantize)

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_stripe_payments",
    name_old: "#{model_name_old}_stripe_payments",
    icon: 'stripe',
    integration: 'stripe',
    is_virtual: true,
    is_read_only: true,
    is_searchable: false,
    pagination_type: 'cursor',
    fields: [
      { field: :id, type: 'String', is_filterable: false },
      { field: :created, type: 'Date', is_filterable: false },
      { field: :amount, type: 'Number', is_filterable: false },
      { field: :status, type: 'String', is_filterable: false },
      { field: :currency, type: 'String', is_filterable: false },
      { field: :refunded, type: 'Boolean', is_filterable: false },
      { field: :description, type: 'String', is_filterable: false },
      {
        field: :customer,
        type: 'String',
        relationship: 'BelongsTo',
        reference: "#{model_name}.id",
        is_filterable: false
      }
    ],
    actions: [
      ForestLiana::Model::Action.new({
        name: 'Refund',
        endpoint: '/forest/stripe_payments/refunds'
      })
    ]
  })

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_stripe_invoices",
    name_old: "#{model_name_old}_stripe_invoices",
    icon: 'stripe',
    integration: 'stripe',
    is_virtual: true,
    is_read_only: true,
    is_searchable: false,
    pagination_type: 'cursor',
    fields: [
      { field: :id, type: 'String', is_filterable: false },
      { field: :amount_due, type: 'Number', is_filterable: false },
      { field: :amount_paid, type: 'Number', is_filterable: false },
      { field: :amount_remaining, type: 'Number', is_filterable: false },
      { field: :application_fee_amount, type: 'Number', is_filterable: false },
      { field: :attempt_count, type: 'Number', is_filterable: false },
      { field: :attempted, type: 'Boolean', is_filterable: false },
      { field: :currency, type: 'String', is_filterable: false },
      { field: :due_date, type: 'Date', is_filterable: false },
      { field: :period_start, type: 'Date', is_filterable: false },
      { field: :period_end, type: 'Date', is_filterable: false },
      { field: :status, type: 'String', enums: ['draft', 'open', 'paid', 'uncollectible', 'void'], is_filterable: false },
      { field: :subtotal, type: 'Number', is_filterable: false },
      { field: :total, type: 'Number', is_filterable: false },
      { field: :tax, type: 'Number', is_filterable: false },
      {
        field: :customer,
        type: 'String',
        relationship: 'BelongsTo',
        reference: "#{model_name}.id",
        is_filterable: false
      }
    ]
  })

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_stripe_cards",
    name_old: "#{model_name_old}_stripe_cards",
    icon: 'stripe',
    integration: 'stripe',
    is_virtual: true,
    is_read_only: true,
    is_searchable: false,
    only_for_relationships: true,
    pagination_type: 'cursor',
    fields: [
      { field: :id, type: 'String', is_filterable: false },
      { field: :last4, type: 'String', is_filterable: false },
      { field: :brand, type: 'String', is_filterable: false },
      { field: :funding, type: 'String', is_filterable: false },
      { field: :exp_month, type: 'Number', is_filterable: false },
      { field: :exp_year, type: 'Number', is_filterable: false },
      { field: :country, type: 'String', is_filterable: false },
      { field: :name, type: 'String', is_filterable: false },
      { field: :address_line1, type: 'String', is_filterable: false },
      { field: :address_line2, type: 'String', is_filterable: false },
      { field: :address_city, type: 'String', is_filterable: false },
      { field: :address_state, type: 'String', is_filterable: false },
      { field: :address_zip, type: 'String', is_filterable: false },
      { field: :address_country, type: 'String', is_filterable: false },
      { field: :cvc_check, type: 'String', is_filterable: false },
      {
        field: :customer,
        type: 'String',
        relationship: 'BelongsTo',
        reference: "#{model_name}.id",
        is_filterable: false
      }
    ]
  })

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_stripe_subscriptions",
    name_old: "#{model_name_old}_stripe_subscriptions",
    icon: 'stripe',
    integration: 'stripe',
    is_virtual: true,
    is_read_only: true,
    is_searchable: false,
    pagination_type: 'cursor',
    fields: [
      { field: :id, type: 'String', is_filterable: false },
      { field: :cancel_at_period_end, type: 'Boolean', is_filterable: false },
      { field: :canceled_at, type: 'Date', is_filterable: false },
      { field: :created, type: 'Date', is_filterable: false },
      { field: :current_period_end, type: 'Date', is_filterable: false },
      { field: :current_period_start, type: 'Date', is_filterable: false },
      { field: :ended_at, type: 'Date', is_filterable: false },
      { field: :livemode, type: 'Boolean', is_filterable: false },
      { field: :quantity, type: 'Number', is_filterable: false },
      { field: :start, type: 'Date', is_filterable: false },
      { field: :status, type: 'String', is_filterable: false },
      { field: :tax_percent, type: 'Number', is_filterable: false },
      { field: :trial_end, type: 'Date', is_filterable: false },
      { field: :trial_start, type: 'Date', is_filterable: false },
      {
        field: :customer,
        type: 'String',
        relationship: 'BelongsTo',
        reference: "#{model_name}.id",
        is_filterable: false
      }
    ]
  })

  ForestLiana.apimap << ForestLiana::Model::Collection.new({
    name: "#{model_name}_stripe_bank_accounts",
    name_old: "#{model_name_old}_stripe_bank_accounts",
    icon: 'stripe',
    integration: 'stripe',
    is_virtual: true,
    is_read_only: true,
    is_searchable: false,
    only_for_relationships: true,
    pagination_type: 'cursor',
    fields: [
      { field: :id, type: 'String', is_filterable: false },
      { field: :account, type: 'String', is_filterable: false },
      { field: :account_holder_name, type: 'String', is_filterable: false },
      { field: :account_holder_type, type: 'String', is_filterable: false },
      { field: :bank_name, type: 'String', is_filterable: false },
      { field: :country, type: 'String', is_filterable: false },
      { field: :currency, type: 'String', is_filterable: false },
      { field: :default_for_currency, type: 'Boolean', is_filterable: false },
      { field: :fingerprint, type: 'String', is_filterable: false },
      { field: :last4, type: 'String', is_filterable: false },
      { field: :rooting_number, type: 'String', is_filterable: false },
      { field: :status, type: 'String', is_filterable: false },
      {
        field: :customer,
        type: 'String',
        relationship: 'BelongsTo',
        reference: "#{model_name}.id",
        is_filterable: false
      }
    ]
  })
end
stripe_integration?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 574
def stripe_integration?
  ForestLiana.integrations
    .try(:[], :stripe)
    .present?
end
stripe_integration_deprecated?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 586
def stripe_integration_deprecated?
  integration = ForestLiana.integrations.try(:[], :stripe)
  is_deprecated = integration.present? && integration.has_key?(:api_key) &&
    integration.has_key?(:user_collection) &&
    integration.has_key?(:user_field)

  if is_deprecated
    integration[:mapping] =
      "#{integration[:user_collection]}.#{integration[:user_field]}"

    FOREST_LOGGER.warn "Stripe integration attributes \"user_collection\" and " \
      "\"user_field\" are now deprecated, please use \"mapping\" attribute."
  end

  is_deprecated
end
stripe_integration_valid?() click to toggle source
# File lib/forest_liana/bootstrapper.rb, line 580
def stripe_integration_valid?
  integration = ForestLiana.integrations.try(:[], :stripe)
  integration.present? && integration.has_key?(:api_key) &&
    integration.has_key?(:mapping)
end