rails_url_shortener 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '0847fa49aa14c40889c11cdf80fd32a846208112f7b1e121455f6c6258225cf8'
4
+ data.tar.gz: 2479208e471351f49be2f9876f33ce22cc6cf6461c62113b0d5e5c66d8bd884a
5
+ SHA512:
6
+ metadata.gz: 94658a6b36105a31e1abc8ce7ac9b67913e2fecec29a834f9898224b1969ac0f593ee72c157bbe149e75a439fe5d68efaa167aebc83758fdd85eb578aef3b047
7
+ data.tar.gz: f40c5f6dc58ab19cd03bd714db4d68431889733579dce5e61c8990964fdc82211cc8d95e20d36d54bdc6909b7f93e871ae3648bd21ab5977123c7c93f2a71fed
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 a-chacon
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # RailsUrlShortener
2
+
3
+ A small rails engine for short urls.
4
+ It could be used like a url shortener or a ip logger, it is your choice.
5
+ The app generate a short url for you and then (if you want) receive the requests and redirect to the original url.
6
+
7
+ Why give your data to a third party app if you can do it by yourself?
8
+
9
+ ## Usage
10
+
11
+ Mount the controller on your app adding the next code on your config/routes.rb:
12
+
13
+ ```ruby
14
+ mount RailsUrlShortener::Engine, at: "/"
15
+
16
+ ```
17
+
18
+ And generate the short links wherever you want using the helper method:
19
+
20
+ ```ruby
21
+ short_url("https://www.github.com/a-chacon/rails_url_shortener")
22
+ ```
23
+
24
+ or model method:
25
+
26
+ ```ruby
27
+ RailsUrlShortener::Url.generate("https://www.github.com/a-chacon/rails_url_shortener")
28
+ ```
29
+
30
+ **Then share the short link.**
31
+
32
+ ### Deeper
33
+
34
+ By default this engine save all request made on your short url, you can use that data for some analitics or simple ip logger. So for get the data in a controller or do wherever you want you can use the Visit model related to a Url:
35
+ ```ruby
36
+ RailsUrlShortener::Url.find_by_key("key").visits # all visits
37
+
38
+ ```
39
+ Or using the model class:
40
+ ```ruby
41
+ RailsUrlShortener::Visit.all # all in database
42
+ ```
43
+
44
+ Also the Url model has a polymorphic relation with an owner that is optional. So you can relate an url whatever you want in your app adding the next relation in a model:
45
+ ```ruby
46
+ has_many :urls, as: :owner
47
+ ```
48
+
49
+ ## Installation
50
+
51
+ Add this line to your application's Gemfile:
52
+
53
+ ```ruby
54
+ gem "rails_url_shortener"
55
+ ```
56
+
57
+ Or install it yourself as:
58
+ ```bash
59
+ gem install rails_url_shortener
60
+ ```
61
+
62
+ Then execute:
63
+ ```bash
64
+ bundle
65
+ ```
66
+
67
+ And finally install the migrations on your project and migrate:
68
+ ```bash
69
+ bin/rails rails_url_shortener:install:migrations db:migrate
70
+ ```
71
+
72
+ If you want the initializer for configurations do:
73
+
74
+ ```bash
75
+ rails generate RailsUrlShortener:initializer
76
+ ```
77
+
78
+ ## Contributing
79
+
80
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
81
+
82
+ If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
83
+ Don't forget to give the project a star! Thanks again!
84
+
85
+ 1. Fork the Project
86
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
87
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
88
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
89
+ 5. Open a Pull Request
90
+
91
+ ## License
92
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1,14 @@
1
+ module RailsUrlShortener
2
+ class UrlsController < ActionController::Metal
3
+ include ActionController::StrongParameters
4
+ include ActionController::Redirecting
5
+ include ActionController::Instrumentation
6
+ include Rails.application.routes.url_helpers
7
+
8
+ def show
9
+ # find, if you pass the request then this is saved
10
+ url = Url.find_by_key(params[:key], request: request)
11
+ redirect_to url.url, status: :moved_permanently
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,4 @@
1
+ module RailsUrlShortener
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,28 @@
1
+ module RailsUrlShortener
2
+ module UrlsHelper
3
+ def short_url(url, owner: nil, key: nil, expires_at: nil, category: nil, url_options: {})
4
+ url_object = Url.generate(
5
+ url,
6
+ owner: owner,
7
+ key: key,
8
+ expires_at: expires_at,
9
+ category: category
10
+ )
11
+
12
+ if url_object.errors.empty?
13
+ # This must be fixed
14
+ # the url_for helper must generate the url
15
+ # options = {
16
+ # controller: "rails_url_shortener_url/urls",
17
+ # action: "show",
18
+ # key: url.key
19
+ # }.merge(url_options)
20
+
21
+ # url_for(options)
22
+ rails_url_shortener_url + url_object.key
23
+ else
24
+ url
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,5 @@
1
+ module RailsUrlShortener
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,88 @@
1
+ module RailsUrlShortener
2
+ class Url < ApplicationRecord
3
+ # variables
4
+ attr_accessor :generating_retries, :key_length
5
+
6
+ # relations
7
+ belongs_to :owner, polymorphic: true, optional: true
8
+ has_many :visits
9
+
10
+ # validations
11
+ validates :key, presence: true, length: { minimum: RailsUrlShortener.minimum_key_length }, uniqueness: true
12
+ validates :url, presence: true, format: URI::DEFAULT_PARSER.make_regexp(%w[http https])
13
+
14
+ # exclude records in which expiration time is set and expiration time is greater than current time
15
+ scope :unexpired, -> { where(arel_table[:expires_at].eq(nil).or(arel_table[:expires_at].gt(::Time.current))) }
16
+
17
+ # callbacks
18
+ before_validation :generate_key
19
+ after_initialize :set_attr
20
+
21
+ ##
22
+ # set default instance variables values
23
+ def set_attr
24
+ @generating_retries = 0
25
+ @key_length = RailsUrlShortener.key_length
26
+ end
27
+
28
+ ##
29
+ # create a url object with the given params
30
+ #
31
+ # if something is wrong return the object with errors
32
+
33
+ def self.generate(url, owner: nil, key: nil, expires_at: nil, category: nil)
34
+ create(
35
+ url: url,
36
+ owner: owner,
37
+ key: key,
38
+ expires_at: expires_at,
39
+ category: category
40
+ )
41
+ end
42
+
43
+ ##
44
+ # find a Url object by the key param
45
+ #
46
+ # if the Url is not found an exception is raised
47
+ ## TODO: and pass query params
48
+ def self.find_by_key!(key, request: nil)
49
+ # Get the token if not exipired
50
+ url = Url.unexpired.find_by!(key: key)
51
+ Visit.parse_and_save(url, request) unless request.nil?
52
+ url
53
+ end
54
+
55
+ ##
56
+ # find a Url object by the key param
57
+ #
58
+ # if the Url is not found the exception is rescue and
59
+ # return a new url object with the default url
60
+
61
+ def self.find_by_key(key, request: nil)
62
+ find_by_key!(key, request: request)
63
+ rescue ActiveRecord::RecordNotFound
64
+ Url.new(
65
+ url: RailsUrlShortener.default_redirect || '/',
66
+ key: 'none'
67
+ )
68
+ end
69
+
70
+ private
71
+
72
+ def key_candidate
73
+ (0...key_length).map { RailsUrlShortener.charset[rand(RailsUrlShortener.charset.size)] }.join
74
+ end
75
+
76
+ def generate_key
77
+ if key.nil?
78
+ loop do
79
+ # plus to the key length if after 10 attempts was not found a candidate
80
+ self.key_length += 1 if generating_retries >= 10
81
+ self.key = key_candidate
82
+ self.generating_retries += 1
83
+ break unless self.class.exists?(key: key)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,31 @@
1
+ module RailsUrlShortener
2
+ require 'json'
3
+ class Visit < ApplicationRecord
4
+ belongs_to :url
5
+
6
+ ##
7
+ # Parse a request information and save
8
+ #
9
+ # Return boolean
10
+
11
+ def self.parse_and_save(url, request)
12
+ # browser detection
13
+ browser = Browser.new(request.headers['User-Agent'])
14
+ if !RailsUrlShortener.save_bots_visits && browser.bot?
15
+ false
16
+ else
17
+ # save
18
+ Visit.create(
19
+ url: url,
20
+ ip: request.ip,
21
+ browser: browser.name,
22
+ browser_version: browser.full_version,
23
+ platform: browser.platform.name,
24
+ platform_version: browser.platform.version,
25
+ bot: browser.bot?,
26
+ user_agent: request.headers['User-Agent']
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ RailsUrlShortener::Engine.routes.draw do
2
+ get '/:key', to: 'urls#show'
3
+ end
@@ -0,0 +1,22 @@
1
+ class CreateRailsUrlShortenerUrls < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :rails_url_shortener_urls do |t|
4
+ # optional if you can link it to a user or other model
5
+ t.references :owner, polymorphic: true, null: true
6
+
7
+ # the real url
8
+ t.text :url, null: false, length: 2048
9
+
10
+ # the unique key
11
+ t.string :key, limit: 10, null: false
12
+
13
+ # category for short url
14
+ t.string :category
15
+
16
+ # valid until date for expirable urls
17
+ t.datetime :expires_at
18
+
19
+ t.timestamps
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ class CreateRailsUrlShortenerVisits < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :rails_url_shortener_visits do |t|
4
+ t.belongs_to :url
5
+ # client ip
6
+ t.string :ip
7
+ # browser from user_agent
8
+ t.string :browser
9
+ # browser version from user_agent
10
+ t.string :browser_version
11
+ # platform from user_agent
12
+ t.string :platform
13
+ # platform version from user_agent
14
+ t.string :platform_version
15
+ # if the request was a bot or not
16
+ t.boolean :bot
17
+ t.string :user_agent
18
+ # variable where we save all data that can be catch from the request
19
+ t.text :meta
20
+
21
+ t.timestamps
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails/generators'
2
+
3
+ class RailsUrlShortenerGenerator < Rails::Generators::Base
4
+
5
+ source_root File.expand_path("templates", __dir__)
6
+
7
+ def copy
8
+ copy_file "initializer.rb", "config/initializers/rails_url_shortener.rb"
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ CHARSETS = {
2
+ alphanum: ('a'..'z').to_a + (0..9).to_a,
3
+ alphacase: ('a'..'z').to_a + ('A'..'Z').to_a,
4
+ alphanumcase: ('A'..'Z').to_a + ('a'..'z').to_a + (0..9).to_a
5
+ }
6
+
7
+ RailsUrlShortener.default_redirect = "/"
8
+ RailsUrlShortener.charset = CHARSETS[:alphanumcase]
9
+ RailsUrlShortener.key_length = 6
10
+ RailsUrlShortener.minimum_key_length = 3
11
+ RailsUrlShortener.save_bots_visits = false
@@ -0,0 +1,6 @@
1
+ module RailsUrlShortener
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace RailsUrlShortener
4
+ require 'browser'
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module RailsUrlShortener
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,37 @@
1
+ require "rails_url_shortener/version"
2
+ require "rails_url_shortener/engine"
3
+
4
+ module RailsUrlShortener
5
+
6
+ ##
7
+ # constants
8
+ CHARSETS = {
9
+ alphanum: ('a'..'z').to_a + (0..9).to_a,
10
+ alphacase: ('a'..'z').to_a + ('A'..'Z').to_a,
11
+ alphanumcase: ('A'..'Z').to_a + ('a'..'z').to_a + (0..9).to_a
12
+ }
13
+
14
+ ##
15
+ # default redirection url when the key isn't found
16
+ mattr_accessor :default_redirect, default: '/'
17
+
18
+ ##
19
+ # charset for generate keys
20
+ mattr_accessor :charset, default: CHARSETS[:alphanumcase]
21
+
22
+ ##
23
+ # default key length used by random keys
24
+ mattr_accessor :key_length, default: 6
25
+
26
+ ##
27
+ # minimum key length for custom keys
28
+ mattr_accessor :minimum_key_length, default: 3
29
+
30
+ ##
31
+ # if save bots visits on db, the detection is provided by browser gem
32
+ # and is described like "The bot detection is quite aggressive"
33
+ # so if you put this configuration like false could lose some visits to your link
34
+ # by default saving all requests
35
+ mattr_accessor :save_bots_visits, default: true
36
+
37
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :rails_url_shortener do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails_url_shortener
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - a-chacon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-04-12 00:00:00.000000000 Z
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
+ - !ruby/object:Gem::Dependency
28
+ name: browser
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 5.3.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 5.3.0
41
+ description: A little engine for rails application that provide url shortener functions.
42
+ email:
43
+ - andres.ch@protonmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - MIT-LICENSE
49
+ - README.md
50
+ - Rakefile
51
+ - app/controllers/rails_url_shortener/urls_controller.rb
52
+ - app/helpers/rails_url_shortener/application_helper.rb
53
+ - app/helpers/rails_url_shortener/urls_helper.rb
54
+ - app/models/rails_url_shortener/application_record.rb
55
+ - app/models/rails_url_shortener/url.rb
56
+ - app/models/rails_url_shortener/visit.rb
57
+ - config/routes.rb
58
+ - db/migrate/20220407202526_create_rails_url_shortener_urls.rb
59
+ - db/migrate/20220407202539_create_rails_url_shortener_visits.rb
60
+ - lib/generators/rails_url_shortener/rails_url_shortener_generator.rb
61
+ - lib/generators/rails_url_shortener/templates/initializer.rb
62
+ - lib/rails_url_shortener.rb
63
+ - lib/rails_url_shortener/engine.rb
64
+ - lib/rails_url_shortener/version.rb
65
+ - lib/tasks/rails_url_shortener_tasks.rake
66
+ homepage: https://www.github.com/a-chacon/rails_url_shortener
67
+ licenses:
68
+ - MIT
69
+ metadata:
70
+ homepage_uri: https://www.github.com/a-chacon/rails_url_shortener
71
+ source_code_uri: https://www.github.com/a-chacon/rails_url_shortener
72
+ changelog_uri: https://www.github.com/a-chacon/rails_url_shortener
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.2.22
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Rails url shortener engine.
92
+ test_files: []