require "resolv" module CartoDB begin CARTODB_REV = File.read("#{Rails.root}/REVISION").strip rescue StandardError CARTODB_REV = nil end DEFAULT_DB_SCHEMA = 'public'.freeze PUBLIC_DB_USER = 'publicuser'.freeze PUBLIC_DB_USER_PASSWORD = 'publicuser'.freeze TILE_DB_USER = 'tileuser'.freeze PG_ADMIN_USER = 'postgres'.freeze SYSTEM_DB_USERS = [PG_ADMIN_USER, TILE_DB_USER, PUBLIC_DB_USER].freeze SRID = 4326 SURROGATE_NAMESPACE_VISUALIZATION = 'rv'.freeze SURROGATE_NAMESPACE_PUBLIC_PAGES = 'rp'.freeze SURROGATE_NAMESPACE_VIZJSON = 'rj'.freeze LAST_BLOG_POSTS_FILE_PATH = "#{Rails.root}/public/system/last_blog_posts.html" # Helper method to encapsulate Rails full URL generation compatible with our subdomainless mode # @param context ActionController::Base or a View or something that holds a request # @param path String Rails route name # @param params Hash (Optional) Parameters to send to the url # @param user ::User (Optional) If not sent will use subdomain or /user/xxx from controller request # @param keep_base_url Boolean (Optional) Keeps the base url from the request in case of subdomainful def self.url(context, path, params: {}, user: nil, keep_base_url: false) base_url = if keep_base_url && !subdomainless_urls? context.request.base_url else CartoDB.base_url_from_request(context.request, user) end # Must clean user_domain or else polymorphic_path will use it and generate again /u/xxx/user/xxx base_url + main_context(context).polymorphic_path(path, params.merge(user_domain: nil)) end # Isolated-context engines need route resolution not in the engine itself but in the main app def self.main_context(context) context.respond_to?(:main_app) && context.main_app ? context.main_app : context end # Helper method to encapsulate Rails base URL generation compatible with our subdomainless mode # @param request A request to extract subdomain and parameters from # @param user ::User (Optional) If not sent will use subdomain or /user/xxx from controller request def self.base_url_from_request(request, user = nil) user ? base_url_from_user(user) : CartoDB.base_url(extract_subdomain(request), nil) end def self.base_url_from_user(user) CartoDB.base_url(user.subdomain, organization_username(user)) end # Helper method to encapsulate Rails URL path generation compatible with our subdomainless mode # @param controller ActionController::Base # @param path String Rails route name # @param params Hash Parameters to send to the url (Optional) def self.path(controller, path, params={}) controller.polymorphic_path(path, params) end # "Smart" subdomain extraction from the request, depending on configuration and /u/xxx url fragment def self.extract_subdomain(request) user_domain = self.username_from_request(request) if user_domain.nil? if subdomainless_urls? && ip?(request.host) '' else subdomain_from_request(request) end else user_domain end end # Raw subdomain extraction from request def self.subdomain_from_request(request) if subdomainless_urls? '' else host = request.host.to_s host.end_with?(session_domain) ? host.gsub(session_domain, '') : '' end end # Flexible subdomain extraction: If /u/xxx or /user/xxxx present uses it, else uses request host (xxx.carto.com) def self.extract_host_subdomain(request) self.username_from_request(request).nil? ? nil : self.subdomain_from_request(request) end # Warning, if subdomains are allowed includes the username as the subdomain, # but else returns a base url WITHOUT '/u/username' def self.base_url(subdomain, org_username=nil, protocol_override=nil) if self.subdomainless_urls? base_url = self.domainless_base_url(subdomain, protocol_override) else base_url = self.subdomain_based_base_url(subdomain, org_username, protocol_override) end base_url end # Note: use ||= only for fields who always have a non-nil, non-false value # else, rely on defined? and pure assignment to allow nils and values caching the value # Stores the non-user part of the domain (e.g. '.carto.com') def self.session_domain @@session_domain ||= self.get_session_domain end def self.domain return @@domain if defined?(@@domain) @@domain = self.get_domain end def self.subdomainless_urls? return @@subdomainless_urls if defined?(@@subdomainless_urls) @@subdomainless_urls = self.get_subdomainless_urls end def self.account_host @@account_host ||= self.get_account_host end def self.account_path @@account_path ||= self.get_account_path end def self.data_library_path @@data_library_path ||= self.get_data_library_path end def self.request_host=(value) @@request_host=value end def self.protocol(protocol_override=nil) default_protocol = self.use_https? ? 'https' : 'http' protocol_override.nil? ? default_protocol : protocol_override end # "private" methods, not intended for direct usage # ------------------------------------------------ def self.organization_username(user) subdomainless_urls? || user.organization.nil? ? nil : user.username end def self.request_host return @@request_host if defined?(@@request_host) @@request_host = '' end def self.hostname @@hostname ||= self.get_hostname end def self.http_port return @@http_port if defined?(@@http_port) @@http_port = self.get_http_port end def self.https_port return @@https_port if defined?(@@https_port) @@https_port = self.get_https_port end def self.subdomain_based_base_url(subdomain, org_username=nil, protocol_override=nil) protocol = self.protocol(protocol_override) base_url ="#{protocol}://#{subdomain}#{self.session_domain}#{protocol == 'http' ? self.http_port : self.https_port}" unless org_username.nil? base_url << "/u/#{org_username}" end base_url end def self.domainless_base_url(subdomain, protocol_override = nil) base_domain = domainless_base_domain(protocol_override) if !subdomain.nil? && !subdomain.empty? "#{base_domain}/user/#{subdomain}" else base_domain end end def self.domainless_base_domain(protocol_override = nil) protocol = self.protocol(protocol_override) port = protocol == 'http' ? http_port : https_port if ip?(request_host) "#{protocol}://#{request_host}#{port}" else request_subdomain = request_host.sub(session_domain, '') request_subdomain += '.' if !request_subdomain.empty? && !request_subdomain.end_with?('.') "#{protocol}://#{request_subdomain}#{session_domain}#{port}" end end def self.base_domain_from_request(request) subdomainless_urls? ? domainless_base_domain : subdomain_based_base_url(subdomain_from_request(request)) end def self.base_domain_from_name(subdomain) subdomainless_urls? ? domainless_base_domain : subdomain_based_base_url(subdomain) end def self.ip?(string) !!(string =~ Resolv::IPv4::Regex) end def self.username_from_request(request) request.params[:user_domain] end def self.get_hostname protocol = self.use_https? ? 'https' : 'http' "#{protocol}://#{self.domain}#{self.http_port}" end def self.get_http_port config_port = Cartodb.config[:http_port] config_port.nil? || config_port == '' || config_port.to_i == 80 ? '' : ":#{config_port}" end def self.get_https_port config_port = Cartodb.config[:https_port] config_port.nil? || config_port == '' || config_port.to_i == 443 ? '' : ":#{config_port}" end def self.get_domain if Rails.env.production? || Rails.env.staging? `hostname -f`.strip elsif Rails.env.development? "vizzuality#{self.session_domain}" else "test#{self.session_domain}" end end def self.use_https? Cartodb.config[:ssl_required] == true end def self.get_session_domain Cartodb.config[:session_domain] end def self.get_subdomainless_urls Cartodb.config[:subdomainless_urls] end def self.get_account_host Cartodb.config[:account_host] end def self.get_account_path Cartodb.config[:account_path] end def self.get_data_library_path Cartodb.config[:data_library] && Cartodb.config[:data_library]['path'] end def self.python_path if Cartodb.config[:importer]['python_path'].blank? "" else Cartodb.config[:importer]['python_path'] end end def self.python_bin_path if Cartodb.config[:importer]['python_bin_path'].blank? `which python`.strip else Cartodb.config[:importer]['python_bin_path'] end end def self.get_absolute_url(url) return unless url.present? uri = URI.parse(url) uri.scheme = protocol unless uri.scheme.present? uri.to_s rescue StandardError nil end def self.unformatted_logger(log_file_path) logger = ::Logger.new(log_file_path) logger.formatter = proc do |_severity, _datetime, _progname, msg| "#{logger_msg2str(msg)}\n" end logger end # Taken from /usr/lib/ruby/2.2.0/logger.rb (msg2str) to mimic standard Logger behaviour def self.logger_msg2str(msg) case msg when ::String msg when ::Exception "#{msg.message} (#{msg.class})\n" << (msg.backtrace || []).join("\n") else msg.inspect end end end