diff --git a/app/serializers/concerns/user_auth_tokens_mixin.rb b/app/serializers/concerns/user_auth_tokens_mixin.rb index 39e6e3232a9..95315c4ed7a 100644 --- a/app/serializers/concerns/user_auth_tokens_mixin.rb +++ b/app/serializers/concerns/user_auth_tokens_mixin.rb @@ -20,7 +20,7 @@ module UserAuthTokensMixin end def location - ipinfo = DiscourseIpInfo.get(client_ip) + ipinfo = DiscourseIpInfo.get(client_ip, I18n.locale) location = [ipinfo[:city], ipinfo[:region], ipinfo[:country]].reject { |x| x.blank? }.join(", ") return I18n.t('staff_action_logs.unknown') if location.blank? diff --git a/lib/discourse_ip_info.rb b/lib/discourse_ip_info.rb index 3623c772559..11703cff79d 100644 --- a/lib/discourse_ip_info.rb +++ b/lib/discourse_ip_info.rb @@ -4,8 +4,12 @@ class DiscourseIpInfo include Singleton def initialize + open_db(File.join(Rails.root, 'vendor', 'data')) + end + + def open_db(path) begin - @mmdb_filename = File.join(Rails.root, 'vendor', 'data', 'GeoLite2-City.mmdb') + @mmdb_filename = File.join(path, 'GeoLite2-City.mmdb') @mmdb = MaxMindDB.new(@mmdb_filename, MaxMindDB::LOW_MEMORY_FILE_READER) @cache = LruRedux::ThreadSafeCache.new(1000) rescue Errno::ENOENT => e @@ -15,7 +19,7 @@ class DiscourseIpInfo end end - def lookup(ip) + def lookup(ip, locale = :en) return {} unless @mmdb begin @@ -26,22 +30,28 @@ class DiscourseIpInfo return {} if !result || !result.found? + locale = locale.to_s.sub('_', '-') + { - country: result.country.name, + country: result.country.name(locale) || result.country.name, country_code: result.country.iso_code, - region: result.subdivisions.most_specific.name, - city: result.city.name, + region: result.subdivisions.most_specific.name(locale) || result.subdivisions.most_specific.name, + city: result.city.name(locale) || result.city.name, } end - def get(ip) + def get(ip, locale = :en) return {} unless @mmdb ip = ip.to_s - @cache[ip] ||= lookup(ip) + @cache["#{ip}-#{locale}"] ||= lookup(ip, locale) end - def self.get(ip) - instance.get(ip) + def self.open_db(path) + instance.open_db(path) + end + + def self.get(ip, locale = :en) + instance.get(ip, locale) end end diff --git a/spec/fixtures/mmdb/GeoLite2-City.mmdb b/spec/fixtures/mmdb/GeoLite2-City.mmdb new file mode 100644 index 00000000000..2e7c95c7ce9 Binary files /dev/null and b/spec/fixtures/mmdb/GeoLite2-City.mmdb differ diff --git a/spec/serializers/user_auth_token_serializer_spec.rb b/spec/serializers/user_auth_token_serializer_spec.rb new file mode 100644 index 00000000000..ef8f9f7cc90 --- /dev/null +++ b/spec/serializers/user_auth_token_serializer_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +describe UserAuthTokenSerializer do + + let(:user) { Fabricate(:user) } + let(:token) { UserAuthToken.generate!(user_id: user.id, client_ip: '2a02:ea00::') } + + before(:each) do + DiscourseIpInfo.open_db(File.join(Rails.root, 'spec', 'fixtures', 'mmdb')) + end + + it 'serializes user auth tokens with respect to user locale' do + I18n.locale = 'de' + json = UserAuthTokenSerializer.new(token, scope: Guardian.new(user), root: false).as_json + expect(json[:location]).to include('Schweiz') + end + + it 'correctly translates Discourse locale to MaxMindDb locale' do + I18n.locale = 'zh_CN' + json = UserAuthTokenSerializer.new(token, scope: Guardian.new(user), root: false).as_json + expect(json[:location]).to include('瑞士') + end +end