Files
baffle-hub/app/services/country_helper.rb

151 lines
4.2 KiB
Ruby

# frozen_string_literal: true
# CountryHelper - Service for country display utilities
#
# Provides methods to convert ISO country codes to display names,
# generate country flags, and format country data for UI components.
class CountryHelper
# Convert ISO code to display name
def self.display_name(iso_code)
return iso_code if iso_code.blank?
country = ISO3166::Country[iso_code]
country.local_name
rescue
iso_code
end
# Convert ISO code to flag emoji
def self.flag_emoji(iso_code)
return "" if iso_code.blank? || iso_code.length != 2
# Convert each letter to regional indicator symbol (A + 0x1F1E5)
iso_code.upcase.codepoints.map { |code| (code + 0x1F1E5).chr }.join
rescue
""
end
# Display name with flag
def self.display_with_flag(iso_code)
return iso_code if iso_code.blank?
"#{display_name(iso_code)} (#{iso_code})"
end
# Check if ISO code is valid
def self.valid_iso_code?(iso_code)
return false if iso_code.blank?
ISO3166::Country[iso_code].present?
rescue
false
end
# Get all countries for select dropdowns
# Returns array of [display_name, iso_code] pairs
def self.all_for_select
ISO3166::Country.all.map do |country|
# Try different name sources in order of preference
# Use the proper countries gem methods
name = country.local_name.presence ||
country.iso_short_name.presence ||
country.common_name.presence ||
country.alpha2
display_name = "#{name} (#{country.alpha2})"
[display_name, country.alpha2]
end.sort_by { |name, _| name }
rescue => e
puts "Error in CountryHelper.all_for_select: #{e.message}"
puts e.backtrace
[]
end
# Get countries by common regions for quick selection
def self.by_region
{
'Americas' => [
'US', 'CA', 'MX', 'BR', 'AR', 'CL', 'CO', 'PE', 'VE'
],
'Europe' => [
'GB', 'DE', 'FR', 'IT', 'ES', 'NL', 'BE', 'CH', 'AT', 'SE',
'NO', 'DK', 'FI', 'PL', 'CZ', 'HU', 'RO', 'GR', 'PT'
],
'Asia Pacific' => [
'CN', 'JP', 'KR', 'IN', 'SG', 'AU', 'NZ', 'TH', 'MY', 'ID',
'PH', 'VN', 'HK', 'TW'
],
'Middle East & Africa' => [
'ZA', 'EG', 'NG', 'KE', 'SA', 'AE', 'IL', 'TR', 'IR'
]
}
rescue
{}
end
# Get countries for specific region with display names
def self.countries_for_region(region_name)
country_codes = by_region[region_name] || []
country_codes.map do |code|
{
code: code,
name: display_name(code),
display: display_with_flag(code)
}
end
end
# Format multiple country targets for display
def self.format_targets(targets)
return [] if targets.blank?
targets.map do |target|
{
code: target,
name: display_name(target),
display: display_with_flag(target)
}
end
end
# Get popular countries for quick blocking (common threat sources)
def self.popular_for_blocking
[
{ code: 'CN', name: 'China', display: '🇨🇳 China', reason: 'High bot/scanner activity' },
{ code: 'RU', name: 'Russia', display: '🇷🇺 Russia', reason: 'State-sponsored attacks' },
{ code: 'IN', name: 'India', display: '🇮🇳 India', reason: 'High spam volume' },
{ code: 'BR', name: 'Brazil', display: '🇧🇷 Brazil', reason: 'Scanner activity' },
{ code: 'IR', name: 'Iran', display: '🇮🇷 Iran', reason: 'Attacks on critical infrastructure' },
{ code: 'KP', name: 'North Korea', display: '🇰🇵 North Korea', reason: 'State-sponsored hacking' }
]
end
# Search countries by name or code
def self.search(query)
return [] if query.blank?
query = query.downcase
ISO3166::Country.all.select do |country|
country.alpha2.downcase.include?(query) ||
country.local_name.downcase.include?(query)
end.first(20).map { |c| [display_with_flag(c.alpha2), c.alpha2] }
rescue
[]
end
# Country statistics for analytics
def self.usage_statistics(country_codes)
return {} if country_codes.blank?
stats = {}
country_codes.each do |code|
stats[code] = {
name: display_name(code),
flag: flag_emoji(code),
display: display_with_flag(code)
}
end
stats
end
end