# frozen_string_literal: true module CoreSystemConfiguration extend ActiveSupport::Concern # # The System configuration. Various configuration items that can be updated/defined at run time # # Use of this class allows you to simply ask for the configuration parameter directly without # first having to get an instance of it. # # SystemConfiguration.queue_impl #=> 'RedisQueue' # # This method only is allowed for accessors, you should NEVER set values on the SystemConfiguration # unless you are updating via the Admin or Stack UI, or during testing to setup a specific configuration # for that. # def self.included(base) base.class_eval do attr_accessor :configuration # # Fields # field :environment, type: String, default: 'test' field :fips_mode, type: Boolean, default: false field :fav_icon_path, { type: String, default: '/favicon.ico' } field :stack_logo_path, { type: String, default: 'ui-company-logo.png' } field :primary_stylesheet, { type: String, default: 'app47' } field :short_cache, { type: Integer, default: 1 } field :medium_cache, { type: Integer, default: 5 } field :long_cache, { type: Integer, default: 15 } # SMTP configuration field :default_email, type: String, default: 'support@app47.com' field :support_email, type: String, default: 'support@app47.com' field :smtp_name, type: String field :smtp_address, type: String field :smtp_domain, type: String field :smtp_port, type: Integer, default: 587 field :smtp_user_name, type: String field :smtp_password, type: String field :smtp_enable_starttls_auto, type: Boolean field :mailgun_api_key, type: String # Twillio support field :twilio_account_id, type: String field :twilio_auth_token, type: String field :twilio_phone_number, type: String # URLs field :base_url, type: String field :cdn_url, type: String # Slack support field :slack_api_url, type: String field :slack_support_channel, type: String, default: 'support' field :slack_sales_channel, type: String, default: 'sales' # Time Zone Support field :default_time_zone, type: String, default: 'US/Eastern' # AWS field :aws_region, type: String field :aws_access_key_id, type: String field :aws_secret_access_key, type: String field :aws_auto_scaling_group_name, type: String # Zendesk field :zendesk_token, type: String field :zendesk_base_url, type: String, default: 'https://app47.zendesk.com' field :zendesk_documentation_path, type: String, default: 'hc' field :zendesk_support_path, type: String, default: 'hc/en-us/requests' field :zendesk_updates_path, type: String, default: 'hc' # Switchboard field :switchboard_base_url, type: String, default: 'https://switchboard.app47.com' field :switchboard_stack_id, type: String field :switchboard_stack_api_token, type: String field :switchboard_last_sync_at, type: Time # # Validations # validates :environment, presence: true, uniqueness: true validates :slack_support_channel, presence: true validates :slack_sales_channel, presence: true validates :default_time_zone, presence: true validates :switchboard_base_url, url: true validates :zendesk_base_url, url: true end base.extend ClassMethods end module ClassMethods def configuration SystemConfiguration.find_or_create_by!(environment: Rails.env) end def smtp_configuration output = {} config = configuration fields = %w[name address domain port user_name password enable_starttls_auto] fields.each do |field| field_name = "smtp_#{field}".to_sym output[field.to_sym] = config.send(field_name) end output end # # NOTE: Currently ignored Codacy issue: When using 'method_missing', fall back on 'super' # def method_missing(method, *args, &_block) if configuration.respond_to?(method) configuration.send(method, *args) else super end end def respond_to?(method_name, include_private = false) configuration.respond_to?(method_name, include_private) || super end def respond_to_missing?(method_name, include_private = false) configuration.respond_to?(method_name, include_private) || super end end # # Make sure the password doesn't get blanked out on an update # def secure_fields super + %i[smtp_password aws_access_secret mailgun_api_key switchboard_stack_api_token twilio_auth_token zendesk_token] end # # Cache times in minutes # def short_cache_time short_cache.minutes end def medium_cache_time medium_cache.minutes end def long_cache_time long_cache.minutes end # # Determine if SMTP is configured # def smtp_configured? smtp_name.present? && smtp_address.present? && smtp_domain.present? end # # Determine if mailgun is configured # def mail_gun_configured? smtp_configured? && mailgun_api_key.present? end # # Determine if AWS is configured # def aws_configured? [aws_region.present?, aws_access_key_id.present?, aws_secret_access_key.present?].all? end # # Determine if auto scaling group is configured # def aws_auto_scaling_configured? aws_configured? && aws_auto_scaling_group_name.present? end # # Return the zendesk documentation URL # def zendesk_documentation_url(user = nil) zendesk_url(forward_to: zendesk_documentation_path, user: user) end # # Return the zendesk support URL # def zendesk_requests_url(user = nil) zendesk_url(forward_to: zendesk_support_path, user: user) end # # Return the zendesk support URL # def zendesk_new_request_url(user = nil) zendesk_url(forward_to: "#{zendesk_support_path}/new", user: user) end # # Return the zendesk update URL # def zendesk_updates_url(user = nil) zendesk_url(forward_to: zendesk_updates_path, user: user) end # # Generate a Zendesk URL # # If a user is passed in and Zendesk is configured then return a JWT enabled URL for # SSO authentication to Zendesk. # def zendesk_url(forward_to: zendesk_documentation_path, user: nil) config = SystemConfiguration.configuration path = if config.zendesk_configured? && user.present? time_now = Time.now.to_i jti = "#{time_now}/#{rand(36 ** 64).to_s(36)}" payload = { jwt: JWT.encode({ iat: time_now, # Seconds since epoch, determine when this token is stale jti: jti, # Unique token identifier, helps prevent replay attacks name: user.name, email: user.email }, config.zendesk_token), return_to: CGI.escape([config.zendesk_base_url, forward_to].join('/')) } ['access/jwt', payload.to_query].join('?') else forward_to end [config.zendesk_base_url, path].join('/') end # # Is zendesk configured? # def zendesk_configured? [zendesk_token.present?, zendesk_base_url.present?, zendesk_documentation_path.present?, zendesk_support_path.present?].all? end # # Public: Determine if switchboard is configured # # Examples # # switchboard_configured? # # => true || false # def switchboard_configured? [switchboard_base_url.present?, switchboard_stack_api_token.present?, switchboard_stack_id.present?].all? end # # Determine if twillio is configured at a system configuration # # Examples # # switchboard_configured? # # => true || false # def twilio_configured? [twilio_account_id.present?, twilio_auth_token.present?, twilio_phone_number.present?].all? end # # Determine if Slack is configured # # Examples # # switchboard_configured? # # => true || false # def slack_configured? slack_api_url.present? end end