rails_url_shortener 0.2.3 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -0
- data/Rakefile +23 -5
- data/app/controllers/rails_url_shortener/urls_controller.rb +2 -0
- data/app/helpers/rails_url_shortener/urls_helper.rb +4 -2
- data/app/jobs/rails_url_shortener/application_job.rb +2 -0
- data/app/jobs/rails_url_shortener/ip_crawler_job.rb +7 -20
- data/app/models/rails_url_shortener/application_record.rb +2 -0
- data/app/models/rails_url_shortener/ipgeo.rb +10 -1
- data/app/models/rails_url_shortener/url.rb +12 -10
- data/app/models/rails_url_shortener/visit.rb +13 -7
- data/db/migrate/20220418184647_create_rails_url_shortener_ipgeos.rb +1 -0
- data/lib/generators/rails_url_shortener/rails_url_shortener_generator.rb +4 -4
- data/lib/generators/rails_url_shortener/templates/initializer.rb +6 -4
- data/lib/rails_url_shortener/engine.rb +2 -0
- data/lib/rails_url_shortener/version.rb +3 -1
- data/lib/rails_url_shortener.rb +6 -6
- data/lib/tasks/rails_url_shortener_tasks.rake +1 -0
- metadata +7 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 20985bb8cc91463fdc5482bd63d3cc20f4d246bd061b2a3379183ab2ef00ebc3
|
4
|
+
data.tar.gz: d84145481a224bbf71071da27a85a2a358190e487cceff531586daa6b245c8e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9df5be0690db7d0939e18a1db2ae9aeb68f243cbc4e1a99ea908ac59099c835b09ebbe89e64c4ba237065419e2de82115519a195d723942452943a5bb58fc298
|
7
|
+
data.tar.gz: 2a2e9fc7fc7180ba824aee0080c65bf1729915171a93ade15f97dd36ade234f39750fe713ed89a83a4fcb0a21d6f7b92d0dab6b95eda4ecfe62c20e3e00de62e
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ A few of the things you can do with RailsUrlShortener:
|
|
15
15
|
* The short links can be associated with a model in your app.
|
16
16
|
* Save interesting things like browser, system and ip data of the 'un-shortened' request.
|
17
17
|
* Temporal short links using the expires_at option.
|
18
|
+
* Get IP data from third part service.
|
18
19
|
|
19
20
|
## Usage
|
20
21
|
|
@@ -80,6 +81,15 @@ Or using the model class:
|
|
80
81
|
RailsUrlShortener::Visit.all # all in database
|
81
82
|
```
|
82
83
|
|
84
|
+
And a Visit is related to a Ipgeo model that contain information about the ip, so you can view this using the active record relation:
|
85
|
+
```ruby
|
86
|
+
RailsUrlShortener::Visit.first.ipgeo # Ipgeo object that contain information of the ip
|
87
|
+
```
|
88
|
+
|
89
|
+
### Ip data
|
90
|
+
|
91
|
+
When a Visit record is created, a job is enqueue for get Ip data from [this](https://ip-api.com/) service and create the Ipgeo record. It is integrated to the free endpoint, so if you think that you have more than 45 different IPS querying in a minute to your app, we need to think in a new solution.
|
92
|
+
|
83
93
|
## Installation
|
84
94
|
|
85
95
|
Add this line to your application's Gemfile:
|
data/Rakefile
CHANGED
@@ -1,8 +1,26 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
load "rails/tasks/engine.rake"
|
3
|
+
require 'bundler/setup'
|
5
4
|
|
6
|
-
|
5
|
+
APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__)
|
6
|
+
load 'rails/tasks/engine.rake'
|
7
7
|
|
8
|
-
|
8
|
+
load 'rails/tasks/statistics.rake'
|
9
|
+
|
10
|
+
require 'bundler/gem_tasks'
|
11
|
+
require 'rake/testtask'
|
12
|
+
|
13
|
+
Rake::TestTask.new(:test) do |t|
|
14
|
+
t.warning = false
|
15
|
+
t.libs << 'test'
|
16
|
+
t.libs << 'lib'
|
17
|
+
t.test_files = FileList['test/**/*test.rb']
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rubocop/rake_task'
|
21
|
+
|
22
|
+
RuboCop::RakeTask.new do |task|
|
23
|
+
task.requires << 'rubocop-minitest'
|
24
|
+
end
|
25
|
+
|
26
|
+
task default: %i[test rubocop]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsUrlShortener
|
2
4
|
module UrlsHelper
|
3
5
|
##
|
@@ -19,8 +21,8 @@ module RailsUrlShortener
|
|
19
21
|
if url_object.errors.empty?
|
20
22
|
# options for url_for
|
21
23
|
options = {
|
22
|
-
controller:
|
23
|
-
action:
|
24
|
+
controller: 'rails_url_shortener/urls',
|
25
|
+
action: 'show',
|
24
26
|
key: url_object.key,
|
25
27
|
host: RailsUrlShortener.host
|
26
28
|
}.merge(url_options)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsUrlShortener
|
2
4
|
class IpCrawlerJob < ApplicationJob
|
3
5
|
queue_as :default
|
@@ -9,32 +11,17 @@ module RailsUrlShortener
|
|
9
11
|
# this function get the ip related data
|
10
12
|
#
|
11
13
|
# create or update an existing record information for an ip
|
12
|
-
|
13
14
|
def perform(visit)
|
14
15
|
if Ipgeo.exists?(ip: visit.ip)
|
15
16
|
ipgeo = Ipgeo.find_by(ip: visit.ip)
|
16
|
-
|
17
|
-
|
18
|
-
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")
|
19
|
-
if ip.code == 200
|
20
|
-
ipgeo.update(JSON.parse(ip.body).transform_keys { |key| key.to_s.underscore }.slice(*Ipgeo.column_names))
|
21
|
-
visit.update(ipgeo: ipgeo)
|
22
|
-
end
|
23
|
-
else
|
24
|
-
visit.update(ipgeo: ipgeo)
|
25
|
-
end
|
17
|
+
# update if older than three months
|
18
|
+
ipgeo.update_from_remote if ipgeo.updated_at <= 3.months.ago
|
26
19
|
elsif !Ipgeo.exists?(ip: visit.ip)
|
27
20
|
# Then create a new record
|
28
|
-
|
29
|
-
|
30
|
-
ipgeo = Ipgeo.new(JSON.parse(ip.body).transform_keys { |key| key.to_s.underscore }.slice(*Ipgeo.column_names))
|
31
|
-
ipgeo.ip = JSON.parse(ip.body)['query']
|
32
|
-
ipgeo.save
|
33
|
-
visit.update(ipgeo: ipgeo)
|
34
|
-
end
|
21
|
+
ipgeo = Ipgeo.create(ip: visit.ip)
|
22
|
+
ipgeo.update_from_remote
|
35
23
|
end
|
36
|
-
|
37
|
-
print('Error' + e.to_s)
|
24
|
+
visit.update(ipgeo: ipgeo) unless ipgeo.nil?
|
38
25
|
end
|
39
26
|
end
|
40
27
|
end
|
@@ -1,5 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsUrlShortener
|
2
4
|
class Ipgeo < ApplicationRecord
|
3
|
-
has_many :visits
|
5
|
+
has_many :visits, dependent: :nullify
|
6
|
+
|
7
|
+
def update_from_remote
|
8
|
+
@ip = HTTP.get("http://ip-api.com/json/#{ip}?fields=status,message,country,countryCode,region,regionName,city,zip,lat,lon,timezone,isp,org,as,mobile,proxy,hosting,query")
|
9
|
+
return unless @ip.code == 200
|
10
|
+
|
11
|
+
update(JSON.parse(@ip.body).transform_keys { |key| key.to_s.underscore }.slice(*Ipgeo.column_names))
|
12
|
+
end
|
4
13
|
end
|
5
14
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsUrlShortener
|
2
4
|
class Url < ApplicationRecord
|
3
5
|
# variables
|
@@ -5,7 +7,7 @@ module RailsUrlShortener
|
|
5
7
|
|
6
8
|
# relations
|
7
9
|
belongs_to :owner, polymorphic: true, optional: true
|
8
|
-
has_many :visits
|
10
|
+
has_many :visits, dependent: :nullify
|
9
11
|
|
10
12
|
# validations
|
11
13
|
validates :key, presence: true, length: { minimum: RailsUrlShortener.minimum_key_length }, uniqueness: true
|
@@ -14,9 +16,9 @@ module RailsUrlShortener
|
|
14
16
|
# exclude records in which expiration time is set and expiration time is greater than current time
|
15
17
|
scope :unexpired, -> { where(arel_table[:expires_at].eq(nil).or(arel_table[:expires_at].gt(::Time.current))) }
|
16
18
|
|
19
|
+
after_initialize :set_attr
|
17
20
|
# callbacks
|
18
21
|
before_validation :generate_key
|
19
|
-
after_initialize :set_attr
|
20
22
|
|
21
23
|
##
|
22
24
|
# set default instance variables values
|
@@ -74,14 +76,14 @@ module RailsUrlShortener
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def generate_key
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
79
|
+
return unless key.nil?
|
80
|
+
|
81
|
+
loop do
|
82
|
+
# plus to the key length if after 10 attempts was not found a candidate
|
83
|
+
self.key_length += 1 if generating_retries >= 10
|
84
|
+
self.key = key_candidate
|
85
|
+
self.generating_retries += 1
|
86
|
+
break unless self.class.exists?(key: key)
|
85
87
|
end
|
86
88
|
end
|
87
89
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module RailsUrlShortener
|
2
4
|
require 'json'
|
3
5
|
class Visit < ApplicationRecord
|
@@ -11,19 +13,19 @@ module RailsUrlShortener
|
|
11
13
|
|
12
14
|
def self.parse_and_save(url, request)
|
13
15
|
# browser detection
|
14
|
-
browser
|
15
|
-
if !RailsUrlShortener.save_bots_visits && browser.bot?
|
16
|
+
browser(request)
|
17
|
+
if !RailsUrlShortener.save_bots_visits && @browser.bot?
|
16
18
|
false
|
17
19
|
else
|
18
20
|
# save
|
19
21
|
visit = Visit.create(
|
20
22
|
url: url,
|
21
23
|
ip: request.ip,
|
22
|
-
browser: browser.name,
|
23
|
-
browser_version: browser.full_version,
|
24
|
-
platform: browser.platform.name,
|
25
|
-
platform_version: browser.platform.version,
|
26
|
-
bot: browser.bot?,
|
24
|
+
browser: @browser.name,
|
25
|
+
browser_version: @browser.full_version,
|
26
|
+
platform: @browser.platform.name,
|
27
|
+
platform_version: @browser.platform.version,
|
28
|
+
bot: @browser.bot?,
|
27
29
|
user_agent: request.headers['User-Agent']
|
28
30
|
)
|
29
31
|
# We enqueue a job for get more data later
|
@@ -31,5 +33,9 @@ module RailsUrlShortener
|
|
31
33
|
visit
|
32
34
|
end
|
33
35
|
end
|
36
|
+
|
37
|
+
def self.browser(request)
|
38
|
+
@browser = Browser.new(request.headers['User-Agent'])
|
39
|
+
end
|
34
40
|
end
|
35
41
|
end
|
@@ -21,6 +21,7 @@ class CreateRailsUrlShortenerIpgeos < ActiveRecord::Migration[7.0]
|
|
21
21
|
add_column :rails_url_shortener_visits, :ipgeo_id, :integer
|
22
22
|
add_index :rails_url_shortener_visits, :ipgeo_id
|
23
23
|
end
|
24
|
+
|
24
25
|
def down
|
25
26
|
remove_column :rails_url_shortener_visits, :ipgeo_id
|
26
27
|
drop_table :rails_url_shortener_ipgeos
|
@@ -1,11 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rails/generators'
|
2
4
|
|
3
5
|
class RailsUrlShortenerGenerator < Rails::Generators::Base
|
4
|
-
|
5
|
-
source_root File.expand_path("templates", __dir__)
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
6
7
|
|
7
8
|
def copy
|
8
|
-
copy_file
|
9
|
+
copy_file 'initializer.rb', 'config/initializers/rails_url_shortener.rb'
|
9
10
|
end
|
10
|
-
|
11
11
|
end
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
CHARSETS = {
|
2
4
|
alphanum: ('a'..'z').to_a + (0..9).to_a,
|
3
5
|
alphacase: ('a'..'z').to_a + ('A'..'Z').to_a,
|
4
|
-
alphanumcase: ('A'..'Z').to_a + ('a'..'z').to_a
|
5
|
-
}
|
6
|
+
alphanumcase: ('A'..'Z').to_a + ('a'..'z').to_a + (0..9).to_a
|
7
|
+
}.freeze
|
6
8
|
|
7
|
-
RailsUrlShortener.host =
|
8
|
-
RailsUrlShortener.default_redirect =
|
9
|
+
RailsUrlShortener.host = 'localhost:3000' # the host used for the helper
|
10
|
+
RailsUrlShortener.default_redirect = '/' # where the users are redirect if the link is not found.
|
9
11
|
RailsUrlShortener.charset = CHARSETS[:alphanumcase] # used for generate the keys, better long.
|
10
12
|
RailsUrlShortener.key_length = 6 # Key length for random generator
|
11
13
|
RailsUrlShortener.minimum_key_length = 3 # minimun permited for a key
|
data/lib/rails_url_shortener.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
|
-
|
2
|
-
require "rails_url_shortener/engine"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
3
|
+
require 'rails_url_shortener/version'
|
4
|
+
require 'rails_url_shortener/engine'
|
5
5
|
|
6
|
+
module RailsUrlShortener
|
6
7
|
##
|
7
8
|
# constants
|
8
9
|
CHARSETS = {
|
9
10
|
alphanum: ('a'..'z').to_a + (0..9).to_a,
|
10
11
|
alphacase: ('a'..'z').to_a + ('A'..'Z').to_a,
|
11
|
-
alphanumcase: ('A'..'Z').to_a + ('a'..'z').to_a
|
12
|
-
}
|
12
|
+
alphanumcase: ('A'..'Z').to_a + ('a'..'z').to_a + (0..9).to_a
|
13
|
+
}.freeze
|
13
14
|
|
14
15
|
##
|
15
16
|
# host for build final url on helper
|
@@ -37,5 +38,4 @@ module RailsUrlShortener
|
|
37
38
|
# so if you put this configuration like false could lose some visits to your link
|
38
39
|
# by default saving all requests
|
39
40
|
mattr_accessor :save_bots_visits, default: true
|
40
|
-
|
41
41
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_url_shortener
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- a-chacon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: rails
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 7.0.2.3
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 7.0.2.3
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: browser
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,9 +52,9 @@ dependencies:
|
|
66
52
|
- - ">="
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: 5.0.4
|
69
|
-
description:
|
70
|
-
|
71
|
-
|
55
|
+
description: |-
|
56
|
+
RailsUrlShortener is a simple engine that provide to your rail's app the functionalities for
|
57
|
+
short URLs. Like bitly.com, but working on your project only.
|
72
58
|
email:
|
73
59
|
- andres.ch@protonmail.com
|
74
60
|
executables: []
|
@@ -101,9 +87,9 @@ licenses:
|
|
101
87
|
- GPL-3.0
|
102
88
|
metadata:
|
103
89
|
bug_tracker_uri: https://www.github.com/a-chacon/rails-url-shortener/issues
|
104
|
-
changelog_uri: https://www.github.com/a-chacon/rails-url-shortener/releases/tag/v0.2.
|
90
|
+
changelog_uri: https://www.github.com/a-chacon/rails-url-shortener/releases/tag/v0.2.6
|
105
91
|
documentation_uri: https://github.com/a-chacon/rails-url-shortener/blob/main/README.md
|
106
|
-
source_code_uri: https://github.com/a-chacon/rails-url-shortener/tree/v0.2.
|
92
|
+
source_code_uri: https://github.com/a-chacon/rails-url-shortener/tree/v0.2.6
|
107
93
|
rubygems_mfa_required: 'true'
|
108
94
|
post_install_message:
|
109
95
|
rdoc_options: []
|