Skip to content

Commit c47737c

Browse files
authored
Merge pull request #3 from a-chacon/add_ip_model
feat: add ipgeo object related to visit with data of ip
2 parents 3cf052f + 68bbf96 commit c47737c

File tree

18 files changed

+326
-23
lines changed

18 files changed

+326
-23
lines changed

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,7 @@ gem "browser"
1313
group :test do
1414
gem 'byebug'
1515
gem 'faker', :git => 'https://github.com/faker-ruby/faker.git', :branch => 'master'
16+
gem "webmock"
1617
end
18+
19+
gem "http"

Gemfile.lock

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ GIT
99
PATH
1010
remote: .
1111
specs:
12-
rails_url_shortener (0.1.3)
12+
rails_url_shortener (0.2.0)
1313
browser (>= 5.3.0)
1414
bundler (>= 1.15.0)
15+
http (>= 5.0.4)
1516
rails (>= 7.0.2.3)
1617

1718
GEM
@@ -82,17 +83,39 @@ GEM
8283
i18n (>= 1.6, < 2)
8384
minitest (>= 5.1)
8485
tzinfo (~> 2.0)
86+
addressable (2.8.0)
87+
public_suffix (>= 2.0.2, < 5.0)
8588
browser (5.3.1)
8689
builder (3.2.4)
8790
byebug (11.1.3)
8891
concurrent-ruby (1.1.10)
92+
crack (0.4.5)
93+
rexml
8994
crass (1.0.6)
9095
digest (3.1.0)
96+
domain_name (0.5.20190701)
97+
unf (>= 0.0.5, < 1.0.0)
9198
erubi (1.10.0)
99+
ffi (1.15.5)
100+
ffi-compiler (1.0.1)
101+
ffi (>= 1.0.0)
102+
rake
92103
globalid (1.0.0)
93104
activesupport (>= 5.0)
105+
hashdiff (1.0.1)
106+
http (5.0.4)
107+
addressable (~> 2.8)
108+
http-cookie (~> 1.0)
109+
http-form_data (~> 2.2)
110+
llhttp-ffi (~> 0.4.0)
111+
http-cookie (1.0.4)
112+
domain_name (~> 0.5)
113+
http-form_data (2.3.0)
94114
i18n (1.10.0)
95115
concurrent-ruby (~> 1.0)
116+
llhttp-ffi (0.4.0)
117+
ffi-compiler (~> 1.0)
118+
rake (~> 13.0)
96119
loofah (2.16.0)
97120
crass (~> 1.0.2)
98121
nokogiri (>= 1.5.9)
@@ -119,6 +142,7 @@ GEM
119142
nio4r (2.5.8)
120143
nokogiri (1.13.3-x86_64-linux)
121144
racc (~> 1.4)
145+
public_suffix (4.0.7)
122146
racc (1.6.0)
123147
rack (2.2.3)
124148
rack-test (1.1.0)
@@ -150,6 +174,7 @@ GEM
150174
thor (~> 1.0)
151175
zeitwerk (~> 2.5)
152176
rake (13.0.6)
177+
rexml (3.2.5)
153178
sprockets (4.0.3)
154179
concurrent-ruby (~> 1.0)
155180
rack (> 1, < 3)
@@ -163,6 +188,13 @@ GEM
163188
timeout (0.2.0)
164189
tzinfo (2.0.4)
165190
concurrent-ruby (~> 1.0)
191+
unf (0.1.4)
192+
unf_ext
193+
unf_ext (0.0.8.1)
194+
webmock (3.14.0)
195+
addressable (>= 2.8.0)
196+
crack (>= 0.3.2)
197+
hashdiff (>= 0.4.0, < 2.0.0)
166198
websocket-driver (0.7.5)
167199
websocket-extensions (>= 0.1.0)
168200
websocket-extensions (0.1.5)
@@ -175,9 +207,11 @@ DEPENDENCIES
175207
browser
176208
byebug
177209
faker!
210+
http
178211
rails_url_shortener!
179212
sprockets-rails
180213
sqlite3
214+
webmock
181215

182216
BUNDLED WITH
183217
2.2.22
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module RailsUrlShortener
2+
class ApplicationJob < ActiveJob::Base
3+
# Automatically retry jobs that encountered a deadlock
4+
# retry_on ActiveRecord::Deadlocked
5+
6+
# Most jobs are safe to ignore if the underlying records are no longer available
7+
# discard_on ActiveJob::DeserializationError
8+
end
9+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
module RailsUrlShortener
2+
class IpCrawlerJob < ApplicationJob
3+
queue_as :default
4+
5+
require 'http'
6+
require 'json'
7+
8+
##
9+
# this function get the ip related data
10+
#
11+
# create or update an existing record information for an ip
12+
13+
def perform(visit)
14+
if Ipgeo.exists?(ip: visit.ip) && Ipgeo.find_by(ip: visit.ip).updated_at <= Time.now - 3.months
15+
# Then update
16+
ip = HTTP.get("http://ip-api.com/json/#{visit.ip}?fields=status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,mobile,proxy,hosting,query")
17+
if ip.code == 200
18+
ipgeo = Ipgeo.find_by(ip: visit.ip)
19+
ipgeo.update(JSON.parse(ip.body).transform_keys { |key| key.to_s.underscore }.slice(*Ipgeo.column_names))
20+
end
21+
elsif !Ipgeo.exists?(ip: visit.ip)
22+
# Then create a new record
23+
ip = HTTP.get("http://ip-api.com/json/#{visit.ip}?fields=status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,mobile,proxy,hosting,query")
24+
if ip.code == 200
25+
ipgeo = Ipgeo.new(JSON.parse(ip.body).transform_keys { |key| key.to_s.underscore }.slice(*Ipgeo.column_names))
26+
ipgeo.ip = JSON.parse(ip.body)['query']
27+
ipgeo.save
28+
visit.ipgeo = ipgeo
29+
end
30+
end
31+
rescue Exception => e
32+
print('Error' + e.to_s)
33+
end
34+
end
35+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module RailsUrlShortener
2+
class Ipgeo < ApplicationRecord
3+
has_many :visits
4+
end
5+
end

app/models/rails_url_shortener/visit.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module RailsUrlShortener
22
require 'json'
33
class Visit < ApplicationRecord
44
belongs_to :url
5+
belongs_to :ipgeo, optional: true
56

67
##
78
# Parse a request information and save
@@ -15,7 +16,7 @@ def self.parse_and_save(url, request)
1516
false
1617
else
1718
# save
18-
Visit.create(
19+
visit = Visit.create(
1920
url: url,
2021
ip: request.ip,
2122
browser: browser.name,
@@ -25,6 +26,9 @@ def self.parse_and_save(url, request)
2526
bot: browser.bot?,
2627
user_agent: request.headers['User-Agent']
2728
)
29+
# We enqueue a job for get more data later
30+
IpCrawlerJob.perform_later(visit)
31+
visit
2832
end
2933
end
3034
end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class CreateRailsUrlShortenerIpgeos < ActiveRecord::Migration[7.0]
2+
def up
3+
create_table :rails_url_shortener_ipgeos do |t|
4+
t.string :ip
5+
t.string :country
6+
t.string :country_code
7+
t.string :region
8+
t.string :region_name
9+
t.string :city
10+
t.string :lat
11+
t.string :lon
12+
t.string :timezone
13+
t.string :isp
14+
t.string :org
15+
t.string :as
16+
t.boolean :mobile
17+
t.boolean :proxy
18+
t.boolean :hosting
19+
t.timestamps
20+
end
21+
add_column :rails_url_shortener_visits, :ipgeo_id, :integer
22+
add_index :rails_url_shortener_visits, :ipgeo_id
23+
end
24+
def down
25+
remove_column :rails_url_shortener_visits, :ipgeo_id
26+
drop_table :rails_url_shortener_ipgeos
27+
end
28+
end

lib/rails_url_shortener/engine.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ module RailsUrlShortener
22
class Engine < ::Rails::Engine
33
isolate_namespace RailsUrlShortener
44
require 'browser'
5+
require 'http'
56
end
67
end

lib/rails_url_shortener/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module RailsUrlShortener
2-
VERSION = "0.1.4"
2+
VERSION = "0.2.0"
33
end

rails_url_shortener.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,6 @@ Gem::Specification.new do |spec|
3232
spec.add_dependency "rails", ">= 7.0.2.3"
3333
spec.add_dependency "browser", ">= 5.3.0"
3434
spec.add_dependency "bundler", ">= 1.15.0"
35+
spec.add_dependency "http", ">= 5.0.4"
3536

3637
end

0 commit comments

Comments
 (0)