shortener 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a06416f117032f4b5b98b0a1b996ae9e8f743394
4
- data.tar.gz: 32ac46718f9be6f242ee57e7b8602a5c7a941772
3
+ metadata.gz: 4c844faf59a32a6bc3c3bbaba68f8281296e010e
4
+ data.tar.gz: d4f9edc81356aba4c03fda63cfb4dac7884f5b30
5
5
  SHA512:
6
- metadata.gz: c1b547ecc5d6bd2dbdfc6bcfe35e232e3413d60cdddedd13059abcca3102704b77d050773936cea57b640df65eb59875cc16905310c1cb774676aa799af89a43
7
- data.tar.gz: 589a1cafc46350a6c0420c9589ef40494cdef914b60afa254ebaa8475f0b464ca22f56e493dfad33f427bb05aa31d67dc92987ab5c684d53b8b017e69c3aa1f2
6
+ metadata.gz: 11178f236215ab473d80bd630337056779e20519d8cde40e48e37f0958ce1b2a9cfb8dea1fc05bd829a23bd6b2e8046481523e7652cd8b8bbdb2ae9220c30188
7
+ data.tar.gz: ce0e61e18cf452f062243d106fab7c5a0c6fac373e018998b57e6d6f08b4ec6902cc66771f7c3b74f93466b800bbc60a10b3db01a4a43fc68c22819a053a5d93
data/README.rdoc CHANGED
@@ -4,8 +4,6 @@
4
4
 
5
5
  Shortener is a Rails Engine Gem that makes it easy to create and interpret shortened URLs on your own domain from within your Rails application. Once installed Shortener will generate, store URLS and "unshorten" shortened URLs for your applications visitors, all whilst collecting basic usage metrics.
6
6
 
7
- ---
8
-
9
7
  == Overview
10
8
 
11
9
  The majority of the Shortener consists of three parts:
@@ -66,13 +64,13 @@ Then add to your routes:
66
64
  The gem can be configured in a config/initializers/shortener.rb file.
67
65
 
68
66
  By default, the shortener will generate keys that are 5 characters long. You can change that by specifying the length of the key like so;
69
- ```
67
+
70
68
  Shortener.unique_key_length = 6
71
- ```
69
+
72
70
  By default, when a unique key isn't matched the site is redirected to "/". You can change that by specifying a different url like so;
73
- ```
71
+
74
72
  Shortener.default_redirect = "http://www.someurl.com"
75
- ```
73
+
76
74
  == Usage
77
75
 
78
76
  To generate a Shortened URL object for the URL "http://example.com" within your controller / models do the following:
@@ -111,10 +109,28 @@ And to access those URLs:
111
109
 
112
110
  You can pass in your own key when generating a shortened URL. This should be unique.
113
111
 
114
- Shortener::ShortenedUrl.instance("example.com", owner: user, custom_key: "my-key")
112
+ Shortener::ShortenedUrl.generate("example.com", owner: user, custom_key: "my-key")
115
113
 
116
114
  short_url("http://example.com", custom_key: 'yourkey')
117
115
 
116
+ === Expirable Shortened URLs
117
+
118
+ You can create expirable URLs.
119
+ Probably, most of the time it would be used with owner:
120
+
121
+ Shortener::ShortenedUrl.generate("example.com/page", user, expires_at: 24.hours.since)
122
+
123
+ You can omit owner passing nil instead:
124
+
125
+ Shortener::ShortenedUrl.generate("example.com/page", nil, expires_at: 24.hours.since)
126
+
127
+ === Forbidden keys
128
+
129
+ You can ensure that records with forbidden keys will not be generated.
130
+ In rails you can put next line into config/initializers/shortener.rb
131
+
132
+ Shortener.forbidden_keys.concat %w(terms promo)
133
+
118
134
  === Shorten URLs in generated emails
119
135
 
120
136
  You can register the included mail interceptor to shorten all links in the emails generated by your Rails app. For example, add to your mailer:
@@ -6,7 +6,7 @@ class Shortener::ShortenedUrlsController < ActionController::Base
6
6
  token = /^([#{Shortener.key_chars.join}]*).*/.match(params[:id])[1]
7
7
 
8
8
  # pull the link out of the db
9
- sl = ::Shortener::ShortenedUrl.find_by_unique_key(token)
9
+ sl = ::Shortener::ShortenedUrl.unexpired.where(unique_key: token).first
10
10
 
11
11
  if sl
12
12
  # don't want to wait for the increment to happen, make it snappy!
@@ -7,6 +7,9 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
7
7
  # allows the shortened link to be associated with a user
8
8
  belongs_to :owner, polymorphic: true
9
9
 
10
+ # exclude records in which expiration time is set and expiration time is greater than current time
11
+ scope :unexpired, -> { where(arel_table[:expires_at].eq(nil).or(arel_table[:expires_at].gt(::Time.current.to_s(:db)))) }
12
+
10
13
  # ensure the url starts with it protocol and is normalized
11
14
  def self.clean_url(url)
12
15
 
@@ -20,28 +23,29 @@ class Shortener::ShortenedUrl < ActiveRecord::Base
20
23
  # generate a shortened link from a url
21
24
  # link to a user if one specified
22
25
  # throw an exception if anything goes wrong
23
- def self.generate!(destination_url, owner: nil, custom_key: nil)
26
+ def self.generate!(destination_url, owner: nil, custom_key: nil, expires_at: nil)
24
27
  # if we get a shortened_url object with a different owner, generate
25
28
  # new one for the new owner. Otherwise return same object
26
29
  if destination_url.is_a? Shortener::ShortenedUrl
27
30
  if destination_url.owner == owner
28
31
  result = destination_url
29
32
  else
30
- result = generate!(destination_url.url, owner: owner, custom_key: custom_key)
33
+ result = generate!(destination_url.url, owner: owner, custom_key: custom_key, expires_at: expires_at)
31
34
  end
32
35
  else
33
36
  scope = owner ? owner.shortened_urls : self
34
- result = scope.where(url: clean_url(destination_url)).first_or_create
37
+ result = scope.where(url: clean_url(destination_url)).first_or_create(unique_key: custom_key, expires_at: expires_at)
35
38
  end
36
39
 
37
40
  result
38
41
  end
39
42
 
40
43
  # return shortened url on success, nil on failure
41
- def self.generate(destination_url, owner: nil, custom_key: nil)
44
+ def self.generate(destination_url, owner: nil, custom_key: nil, expires_at: nil)
42
45
  begin
43
- generate!(destination_url, owner: owner, custom_key: custom_key)
44
- rescue
46
+ generate!(destination_url, owner: owner, custom_key: custom_key, expires_at: expires_at)
47
+ rescue => e
48
+ logger.info e
45
49
  nil
46
50
  end
47
51
  end
@@ -14,6 +14,9 @@ class CreateShortenedUrlsTable < ActiveRecord::Migration
14
14
  # how many times the link has been clicked
15
15
  t.integer :use_count, null: false, default: 0
16
16
 
17
+ # valid until date for expirable urls
18
+ t.datetime :expires_at
19
+
17
20
  t.timestamps
18
21
  end
19
22
 
data/lib/shortener.rb CHANGED
@@ -24,6 +24,10 @@ module Shortener
24
24
  mattr_accessor :default_redirect
25
25
  self.default_redirect = '/'
26
26
 
27
+ # forbidden keys
28
+ mattr_accessor :forbidden_keys
29
+ self.forbidden_keys = []
30
+
27
31
  def self.key_chars
28
32
  CHARSETS[charset]
29
33
  end
@@ -1,3 +1,3 @@
1
1
  module Shortener
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.2"
3
3
  end
data/shortener.gemspec CHANGED
@@ -22,4 +22,4 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "byebug"
23
23
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
24
24
  s.require_path = 'lib'
25
- end
25
+ end
@@ -12,9 +12,6 @@ describe Shortener::ShortenedUrlsController, type: :controller do
12
12
 
13
13
  context 'valid keys' do
14
14
  context 'real key' do
15
- before do
16
- short_url
17
- end
18
15
  let(:key) { short_url.unique_key }
19
16
 
20
17
  it 'redirects to the destination url' do
@@ -71,6 +68,16 @@ describe Shortener::ShortenedUrlsController, type: :controller do
71
68
  end
72
69
  end
73
70
  end
71
+
72
+ context 'expired code' do
73
+ let(:expired_url) { Shortener::ShortenedUrl.generate(Faker::Internet.url, expires_at: 1.hour.ago) }
74
+ describe "GET show with expired code" do
75
+ let(:key) { expired_url.unique_key }
76
+ it 'redirects to the default url' do
77
+ expect(response).to redirect_to Shortener.default_redirect
78
+ end
79
+ end
80
+ end
74
81
  end
75
82
  end
76
83
  end
@@ -11,7 +11,7 @@ Dummy::Application.configure do
11
11
 
12
12
  # Show full error reports and disable caching
13
13
  config.consider_all_requests_local = true
14
- config.action_view.debug_rjs = true
14
+ #config.action_view.debug_rjs = true
15
15
  config.action_controller.perform_caching = false
16
16
 
17
17
  # Print deprecation notices to the Rails logger
@@ -6,7 +6,7 @@ class CreateShortenedUrlsTable < ActiveRecord::Migration
6
6
  t.string :owner_type, limit: 20
7
7
 
8
8
  # the real url that we will redirect to
9
- t.string :url, null: false
9
+ t.text :url, null: false
10
10
 
11
11
  # the unique key
12
12
  t.string :unique_key, limit: 10, null: false
@@ -14,6 +14,9 @@ class CreateShortenedUrlsTable < ActiveRecord::Migration
14
14
  # how many times the link has been clicked
15
15
  t.integer :use_count, null: false, default: 0
16
16
 
17
+ # valid until date for expirable urls
18
+ t.datetime :expires_at
19
+
17
20
  t.timestamps
18
21
  end
19
22
 
@@ -0,0 +1,9 @@
1
+ class ChangeUrlFieldToTextOnShortenedUrl < ActiveRecord::Migration
2
+ # def up
3
+ # change_column :shortened_urls, :url, :text
4
+ # end
5
+
6
+ # def down
7
+ # change_column :shortened_urls, :url, :string
8
+ # end
9
+ end
@@ -0,0 +1,5 @@
1
+ class AddExpiresAtToShortenedUrl < ActiveRecord::Migration
2
+ # def change
3
+ # add_column :shortened_urls, :expires_at, :datetime
4
+ # end
5
+ end
@@ -9,26 +9,28 @@
9
9
  # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
10
  # you'll amass, the slower it'll run and the greater likelihood for issues).
11
11
  #
12
- # It's strongly recommended to check this file into your version control system.
12
+ # It's strongly recommended that you check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20120214023758) do
14
+ ActiveRecord::Schema.define(version: 20150919033108) do
15
15
 
16
- create_table "shortened_urls", :force => true do |t|
16
+ create_table "shortened_urls", force: true do |t|
17
17
  t.integer "owner_id"
18
- t.string "owner_type", :limit => 20
19
- t.string "url", :null => false
20
- t.string "unique_key", :limit => 10, :null => false
21
- t.integer "use_count", :default => 0, :null => false
22
- t.datetime "created_at", :null => false
23
- t.datetime "updated_at", :null => false
18
+ t.string "owner_type", limit: 20
19
+ t.text "url", null: false
20
+ t.string "unique_key", limit: 10, null: false
21
+ t.integer "use_count", default: 0, null: false
22
+ t.datetime "expires_at"
23
+ t.datetime "created_at"
24
+ t.datetime "updated_at"
24
25
  end
25
26
 
26
- add_index "shortened_urls", ["owner_id", "owner_type"], :name => "index_shortened_urls_on_owner_id_and_owner_type"
27
- add_index "shortened_urls", ["unique_key"], :name => "index_shortened_urls_on_unique_key", :unique => true
27
+ add_index "shortened_urls", ["owner_id", "owner_type"], name: "index_shortened_urls_on_owner_id_and_owner_type"
28
+ add_index "shortened_urls", ["unique_key"], name: "index_shortened_urls_on_unique_key", unique: true
29
+ add_index "shortened_urls", ["url"], name: "index_shortened_urls_on_url"
28
30
 
29
- create_table "users", :force => true do |t|
30
- t.datetime "created_at", :null => false
31
- t.datetime "updated_at", :null => false
31
+ create_table "users", force: true do |t|
32
+ t.datetime "created_at"
33
+ t.datetime "updated_at"
32
34
  end
33
35
 
34
36
  end
@@ -62,6 +62,33 @@ describe Shortener::ShortenedUrl, type: :model do
62
62
  end
63
63
  end
64
64
 
65
+ context 'same url as existing' do
66
+ it 'returns the same shortened link record' do
67
+ expect(Shortener::ShortenedUrl.generate!(url)).to eq existing_shortened_url
68
+ end
69
+ end
70
+
71
+ context 'same url as existing, but with a different owner' do
72
+ let(:owner) { User.create }
73
+ it 'returns the a new shortened link record' do
74
+ expect(Shortener::ShortenedUrl.generate!(url, owner: owner)).not_to eq existing_shortened_url
75
+ end
76
+ end
77
+
78
+ context 'existing shortened url as argument' do
79
+ let(:owner) { User.create }
80
+ it 'returns the a new shortened link record' do
81
+ expect(Shortener::ShortenedUrl.generate!(existing_shortened_url)).to eq existing_shortened_url
82
+ end
83
+ end
84
+
85
+ context 'existing shortened url as argument, with new owner' do
86
+ let(:owner) { User.create }
87
+ it 'returns the a new shortened link record' do
88
+ expect(Shortener::ShortenedUrl.generate!(existing_shortened_url, owner: owner)).not_to eq existing_shortened_url
89
+ end
90
+ end
91
+
65
92
  context "duplicate unique key" do
66
93
  before do
67
94
  expect_any_instance_of(Shortener::ShortenedUrl).to receive(:generate_unique_key).
@@ -101,4 +128,17 @@ describe Shortener::ShortenedUrl, type: :model do
101
128
  end
102
129
  end
103
130
  end
131
+
132
+ describe 'unexpired scope' do
133
+ let(:permanent_url) { described_class.generate(Faker::Internet.url) }
134
+ let!(:expired_url) { described_class.generate(Faker::Internet.url, expires_at: 2.hour.ago) }
135
+ let!(:unexpired_url) { described_class.generate(Faker::Internet.url, expires_at: 1.hour.since) }
136
+ let!(:unexpired_scope) { described_class.unexpired }
137
+
138
+ it "should contain permanent and unexpired records" do
139
+ expect(unexpired_scope).to include(permanent_url)
140
+ expect(unexpired_scope).to include(unexpired_url)
141
+ expect(unexpired_scope).not_to include(expired_url)
142
+ end
143
+ end
104
144
  end
@@ -0,0 +1,16 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ # user defined in dummy app, uses has_shortened_urls
5
+ describe User do
6
+ it { should have_many :shortened_urls }
7
+
8
+ context 'shortened url created with owner' do
9
+ let (:user) { User.create }
10
+ let (:shortened_url) { Shortener::ShortenedUrl.generate(Faker::Internet.url, owner: user) }
11
+ specify 'shorted_urls will contains the url' do
12
+ expect(user.shortened_urls).to include shortened_url
13
+ expect(user.shortened_urls.size).to be 1
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shortener
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - James P. McGrath
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-09-18 00:00:00.000000000 Z
12
+ date: 2015-09-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -115,7 +115,6 @@ files:
115
115
  - app/controllers/shortener/shortened_urls_controller.rb
116
116
  - app/helpers/shortener/shortener_helper.rb
117
117
  - app/models/shortener/shortened_url.rb
118
- - config/routes.rb
119
118
  - lib/generators/shortener/shortener_generator.rb
120
119
  - lib/generators/shortener/templates/migration.rb
121
120
  - lib/shortener.rb
@@ -149,11 +148,14 @@ files:
149
148
  - spec/dummy/db/.gitkeep
150
149
  - spec/dummy/db/migrate/20120213084304_create_shortened_urls_table.rb
151
150
  - spec/dummy/db/migrate/20120214023758_create_users.rb
151
+ - spec/dummy/db/migrate/20150919033038_change_url_field_to_text_on_shortened_url.rb
152
+ - spec/dummy/db/migrate/20150919033108_add_expires_at_to_shortened_url.rb
152
153
  - spec/dummy/db/schema.rb
153
154
  - spec/dummy/public/favicon.ico
154
155
  - spec/dummy/script/rails
155
156
  - spec/helpers/shortener_helper_spec.rb
156
157
  - spec/models/shortened_url_spec.rb
158
+ - spec/models/user_spec.rb
157
159
  - spec/shortener/shorten_url_interceptor_spec.rb
158
160
  - spec/spec_helper.rb
159
161
  homepage: http://jamespmcgrath.com/projects/shortener
data/config/routes.rb DELETED
@@ -1,3 +0,0 @@
1
- Rails.application.routes.draw do
2
- get '/s/:unique_key', to: 'shortener/shortened_urls#translate', as: 'shortener_translate'
3
- end