SpeciesFileGroup/taxonworks

View on GitHub
lib/settings.rb

Summary

Maintainability
A
3 hrs
Test Coverage
# Server/application configuration settings

require 'utilities'
require 'utilities/hashes'
require 'taxonworks_net'
module Settings

  class Error < RuntimeError; end;

  EXCEPTION_NOTIFICATION_SETTINGS = [
    :email_prefix,
    :sender_address,
    :exception_recipients
  ].freeze

  VALID_SECTIONS = [
    :backup_directory,
    :default_data_directory,
    :exception_notification,
    :action_mailer_smtp_settings,
    :action_mailer_url_host,
    :mail_domain,
    :capistrano,
    :interface,
    :selenium
  ].freeze

  @@backup_directory = nil
  @@default_data_directory = nil
  @@mail_domain = nil
  @@config_hash = nil

  @@sandbox_mode = false
  @@sandbox_commit_sha = nil
  @@sandbox_short_commit_sha = nil
  @@sandbox_commit_date = nil

  @@selenium_settings = {}

  # @param [Hash] config
  # @param [Hash] hash
  # @return [Boolean]
  def self.load_from_hash(config, hash)
    invalid_sections = hash.keys - VALID_SECTIONS
    raise Error, "#{invalid_sections} are not valid sections" unless invalid_sections.empty?

    @@config_hash = hash.deep_dup

    load_exception_notification(config, hash[:exception_notification])
    load_default_data_directory(hash[:default_data_directory])
    load_backup_directory(hash[:backup_directory])
    load_action_mailer_smtp_settings(config, hash[:action_mailer_smtp_settings])
    load_action_mailer_url_host(config, hash[:action_mailer_url_host])
    load_mail_domain(config, hash[:mail_domain])
    load_interface(hash[:interface])
    load_selenium_config(hash[:selenium]) if hash[:selenium]
    true
  end

  # @return [Hash]
  def self.get_config_hash
    @@config_hash
  end

  # @param [Hash] config
  # @param [String] path
  # @param [Symbol] set_name
  def self.load_from_file(config, path, set_name)
    hash = YAML.load_file(path)
    if hash.keys.include?(set_name.to_s)
      self.load_from_hash(config, Utilities::Hashes.symbolize_keys(hash[set_name.to_s] || { }))
    else
      # require settings for production, but technically not test/development
      raise Error, "#{set_name} settings set not found" unless %w{production test development}.include?(set_name.to_s)
    end
  end

  # @param [Hash] config
  # @param [Symbol] set_name
  def self.load_from_settings_file(config, set_name)
    self.load_from_file(config, 'config/application_settings.yml', set_name) if File.exist?('config/application_settings.yml')
  end

  # @return [String]
  def self.default_data_directory
    @@default_data_directory
  end

  # @return [String]
  def self.backup_directory
    @@backup_directory
  end

  # @return [String]
  def self.mail_domain
    @@mail_domain
  end

  # @return [Boolean]
  def self.sandbox_mode?
    @@sandbox_mode
  end

  # @return [String]
  def self.sandbox_commit_sha
    @@sandbox_commit_sha
  end

  # @return [String]
  def self.sandbox_short_commit_sha
    @@sandbox_short_commit_sha
  end

  # @return [Date]
  def self.sandbox_commit_date
    @@sandbox_commit_date
  end

  # @return [Hash]
  def self.selenium_settings
    @@selenium_settings
  end

  # @param [String] path
  def self.setup_directory(path)
    if !Dir.exist?(path)
      # TODO: use/open a logger
      Rainbow("Directory #{path} does not exist, creating").purple
      FileUtils.mkdir_p(path)
      raise Error, "Directory #{path} could not be made, check permissions" unless Dir.exist?(path)
    end
  end

  # @param [String] path
  # @return [String]
  def self.load_default_data_directory(path)
    @@default_data_directory = nil
    if !path.nil?
      full_path = File.absolute_path(path)
      setup_directory(full_path)
      @@default_data_directory = full_path
    end
  end

  # @param [String] path
  # @return [String]
  def self.load_backup_directory(path)
    @@backup_directory = nil
    if !path.nil?
      full_path = File.absolute_path(path)
      setup_directory(full_path)
      @@backup_directory = full_path
    end
  end

  # @param [Hash] config
  # @param [Hash] settings
  def self.load_exception_notification(config, settings)
    if settings
      config.middleware.use ExceptionNotification::Rack, email: process_exception_notification(settings)
    end
  end

  # @param [Hash] settings
  # @return [Hash]
  def self.process_exception_notification(settings)
    missing = EXCEPTION_NOTIFICATION_SETTINGS - settings.keys
    raise Error, "Missing #{missing} settings in exception_notification" unless missing.empty?

    invalid = settings.keys - EXCEPTION_NOTIFICATION_SETTINGS
    raise Error, "#{invalid} are not valid settings for exception_notification" unless invalid.empty?

    settings[:exception_recipients] = settings[:exception_recipients].split(',') unless settings[:exception_recipients].class == Array || settings[:exception_recipients].blank?

    settings[:sections] = %w{github_link request session environment backtrace full_backtrace}

    raise Error, ':exception_recipients must be an Array' unless settings[:exception_recipients].class == Array

    settings
  end

  # @param [Hash] settings
  def self.load_interface(settings)
    if settings
      invalid = settings.keys - [:sandbox_mode]
      raise Error, "#{invalid} are not valid settings for interface" unless invalid.empty?
      if settings[:sandbox_mode] == true
        @@sandbox_mode = true
        @@sandbox_commit_sha = TaxonworksNet.commit_sha
        @@sandbox_short_commit_sha = TaxonworksNet.commit_sha.try(:slice!, 0, 12)
        @@sandbox_commit_date = TaxonworksNet.commit_date
      end
    end
  end

  # @param [Hash] settings
  # @return [Hash]
  def self.load_selenium_config(settings)
    invalid = settings.keys - [:browser, :marionette, :firefox_binary_path, :chromedriver_path, :headless]

    raise Error, "#{invalid} are not valid settings for test:selenium." unless invalid.empty?
    raise Error, "Can not find Firefox browser binary #{settings[:firefox_binary_path]}." if settings[:browser] == :firefox && !settings[:firefox_binary_path].blank? && !File.exist?(settings[:firefox_binary_path])
    raise Error, "Can not find chromedriver #{ settings[:chromedriver_path] }." if settings[:browser] == :chrome && !settings[:chromedriver_path].blank? && !File.exist?(settings[:chromedriver_path])

    settings.each do |k,v|
      @@selenium_settings[k] = v if !v.blank?
    end
  end

  # @param [Hash] config
  # @param [Hash] settings
  # @return [Hash]
  def self.load_action_mailer_smtp_settings(config, settings)
    if settings
      auth = {}
      user = ENV['TW_ACTION_MAILER_SMTP_SETTINGS_USER_NAME']
      pass = ENV['TW_ACTION_MAILER_SMTP_SETTINGS_PASSWORD']
      auth[:user_name] = user unless user.blank?
      auth[:password] = pass unless pass.blank?

      config.action_mailer.delivery_method = :smtp
      config.action_mailer.smtp_settings = {
        openssl_verify_mode: 'none',
      }.merge(auth).merge(settings)
    end
  end

  # @param [Hash] config
  # @param [String] url_host
  # @return [Boolean]
  def self.load_action_mailer_url_host(config, url_host)
    if url_host
      (config.action_mailer.default_url_options ||= {}).merge!({host: url_host})
    end
  end

  # @param [Hash] config
  # @param [String] mail_domain
  # @return [String]
  def self.load_mail_domain(config, mail_domain)
    @@mail_domain = mail_domain
  end

  # @param [Hash] config
  # @return [Boolean]
  def self.load_test_defaults(config)
    load_from_hash(config, {
      exception_notification: {
        email_prefix: '[TW-Error] ',
        sender_address: %{"notifier" <notifier@example.com>},
        exception_recipients: %w{exceptions@example.com},
      },
      mail_domain: 'example.com',
      selenium: {
        browser: 'firefox',
        marionette: false,
        firefox_binary_path: nil,
        chromedriver_path: nil
      }
    })
  end

end