feat: IP lookup (#1315)

- feature to store contact IP for accounts
- IP lookup through geocoder gem
- ability to do IP lookup through external APIs
- add commit hook to prevent push to develop and master
- migrations to fix default values for jsonb columns
This commit is contained in:
Sojan Jose
2020-10-28 02:14:36 +05:30
committed by GitHub
parent ff96d43953
commit 1d9debaee0
16 changed files with 163 additions and 9 deletions

View File

@@ -19,13 +19,16 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def create
ActiveRecord::Base.transaction do
@contact = Current.account.contacts.new(contact_params)
set_ip
@contact.save!
@contact_inbox = build_contact_inbox
end
end
def update
@contact.update!(contact_update_params)
@contact.assign_attributes(contact_update_params)
set_ip
@contact.save!
rescue ActiveRecord::RecordInvalid => e
render json: {
message: e.record.errors.full_messages.join(', '),
@@ -67,4 +70,11 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def fetch_contact
@contact = Current.account.contacts.includes(contact_inboxes: [:inbox]).find(params[:id])
end
def set_ip
return if @contact.account.feature_enabled?('ip_lookup')
@contact[:additional_attributes][:created_at_ip] ||= request.remote_ip
@contact[:additional_attributes][:updated_at_ip] = request.remote_ip
end
end

View File

@@ -0,0 +1,57 @@
require 'rubygems/package'
class ContactIpLookupJob < ApplicationJob
queue_as :default
def perform(contact)
return unless ensure_look_up_service
update_contact_location_from_ip(contact)
rescue Errno::ETIMEDOUT => e
Rails.logger.info "Exception: ip resolution failed : #{e.message}"
end
private
def ensure_look_up_service
return if ENV['IP_LOOKUP_SERVICE'].blank? || ENV['IP_LOOKUP_API_KEY'].blank?
return true if ENV['IP_LOOKUP_SERVICE'].to_sym != :geoip2
ensure_look_up_db
end
def update_contact_location_from_ip(contact)
ip = get_contact_ip(contact)
return if ip.blank?
contact.additional_attributes['city'] = Geocoder.search(ip).first.city
contact.additional_attributes['country'] = Geocoder.search(ip).first.country
contact.save!
end
def get_contact_ip(contact)
contact.additional_attributes['updated_at_ip'] || contact.additional_attributes['created_at_ip']
end
def ensure_look_up_db
return true if File.exist?(GeocoderConfiguration::LOOK_UP_DB)
setup_vendor_db
end
def setup_vendor_db
base_url = 'https://download.maxmind.com/app/geoip_download'
source = URI.open("#{base_url}?edition_id=GeoLite2-City&suffix=tar.gz&license_key=#{ENV['IP_LOOKUP_API_KEY']}")
tar_extract = Gem::Package::TarReader.new(Zlib::GzipReader.open(source))
tar_extract.rewind
tar_extract.each do |entry|
next unless entry.full_name.include?('GeoLite2-City.mmdb') && entry.file?
File.open GeocoderConfiguration::LOOK_UP_DB, 'wb' do |f|
f.print entry.read
end
return true
end
end
end

View File

@@ -40,6 +40,7 @@ class Contact < ApplicationRecord
before_validation :prepare_email_attribute
after_create_commit :dispatch_create_event
after_update_commit :dispatch_update_event
after_commit :ip_lookup
def get_source_id(inbox_id)
contact_inboxes.find_by!(inbox_id: inbox_id).source_id
@@ -68,6 +69,12 @@ class Contact < ApplicationRecord
}
end
def ip_lookup
return unless account.feature_enabled?('ip_lookup')
ContactIpLookupJob.perform_later(self)
end
def prepare_email_attribute
# So that the db unique constraint won't throw error when email is ''
self.email = nil if email.blank?