shortener 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.rdoc +16 -0
- data/app/controllers/shortener/shortened_urls_controller.rb +4 -1
- data/lib/shortener.rb +1 -0
- data/lib/shortener/railtie.rb +3 -1
- data/lib/shortener/shorten_url_interceptor.rb +63 -0
- data/lib/shortener/version.rb +1 -1
- data/spec/controllers/shortened_urls_controller_spec.rb +30 -9
- data/spec/dummy/config/application.rb +3 -5
- data/spec/shortener/shorten_url_interceptor_spec.rb +62 -0
- metadata +13 -11
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -77,6 +77,22 @@ And to access those URLs:
|
|
77
77
|
|
78
78
|
user.shortened_urls
|
79
79
|
|
80
|
+
=== Shorten URLs in generated emails
|
81
|
+
|
82
|
+
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:
|
83
|
+
|
84
|
+
class MyMailer < ActionMailer::Base
|
85
|
+
register_interceptor Shortener::ShortenUrlInterceptor.new
|
86
|
+
end
|
87
|
+
|
88
|
+
This will replace all long URLs in the emails generated by MyMailer with shortened versions. The base URL for the shortener will be infered from the mailer's default_url_options. If you use a different hostname for your shortener, you can use:
|
89
|
+
|
90
|
+
class MyMailer < ActionMailer::Base
|
91
|
+
register_interceptor Shortener::ShortenUrlInterceptor.new :base_url => "http://shortener.host"
|
92
|
+
end
|
93
|
+
|
94
|
+
The interceptor supports a few more arguments, see the implementation for details.
|
95
|
+
|
80
96
|
== Origins
|
81
97
|
|
82
98
|
Shortener is based on code from Dealush[http://dealush.com], for a bit of backstory to Shortener see this {blog post}[http://jamespmcgrath.com/a-simple-link-shortener-in-rails/].
|
@@ -2,8 +2,11 @@ class Shortener::ShortenedUrlsController < ActionController::Base
|
|
2
2
|
|
3
3
|
# find the real link for the shortened link key and redirect
|
4
4
|
def show
|
5
|
+
# only use the leading valid characters
|
6
|
+
token = /^([#{Shortener.key_chars.join}]*).*/.match(params[:id])[1]
|
7
|
+
|
5
8
|
# pull the link out of the db
|
6
|
-
sl = ::Shortener::ShortenedUrl.find_by_unique_key(
|
9
|
+
sl = ::Shortener::ShortenedUrl.find_by_unique_key(token)
|
7
10
|
|
8
11
|
if sl
|
9
12
|
# don't want to wait for the increment to happen, make it snappy!
|
data/lib/shortener.rb
CHANGED
data/lib/shortener/railtie.rb
CHANGED
@@ -6,6 +6,8 @@ class Shortener::Railtie < ::Rails::Railtie #:nodoc:
|
|
6
6
|
ActiveSupport.on_load :active_record do
|
7
7
|
extend Shortener::ActiveRecordExtension
|
8
8
|
end
|
9
|
-
|
9
|
+
ActiveSupport.on_load :action_view do
|
10
|
+
include Shortener::ShortenerHelper
|
11
|
+
end
|
10
12
|
end
|
11
13
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Shortener
|
3
|
+
=begin
|
4
|
+
The Shorten URL Interceptor is a mail interceptor which shortens any URLs
|
5
|
+
in generated emails.
|
6
|
+
|
7
|
+
Usage:
|
8
|
+
|
9
|
+
class MyMailer < ActionMailer::Base
|
10
|
+
register_interceptor Shortener::ShortenUrlInterceptor.new
|
11
|
+
end
|
12
|
+
=end
|
13
|
+
class ShortenUrlInterceptor
|
14
|
+
|
15
|
+
DEFAULT_NOT_SHORTEN = [ 'twitter\.com/',
|
16
|
+
'facebook\.com/',
|
17
|
+
'cloudfront\.net/' ].map {|r| Regexp.new(r) }
|
18
|
+
DEFAULT_LENGTH_THRESHOLD = 20
|
19
|
+
|
20
|
+
URL_REGEX = /\b((https?):\/\/\w+\.)[-A-Z0-9+&@#\/%?=~_|$!:,.;]*[-A-Z0-9+&@#\/%=~_|$]/i
|
21
|
+
MIME_TYPES = %w(text/plain text/html application/xhtml+xml)
|
22
|
+
|
23
|
+
def initialize(opts = {})
|
24
|
+
@not_shorten = opts[:not_shorten] || DEFAULT_NOT_SHORTEN
|
25
|
+
@length_threshold = opts[:length_threshold] || DEFAULT_LENGTH_THRESHOLD
|
26
|
+
@base_url = opts[:base_url] || ShortenUrlInterceptor.infer_base_url
|
27
|
+
end
|
28
|
+
|
29
|
+
def delivering_email(email)
|
30
|
+
[email, email.all_parts].flatten.compact.each do |part|
|
31
|
+
if MIME_TYPES.include?(part.mime_type)
|
32
|
+
part.body = part.body.decoded.gsub(URL_REGEX) do |url|
|
33
|
+
shorten_url(url)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def shorten_url(url)
|
42
|
+
if url.length > @length_threshold && ! @not_shorten.any?{|r| r =~ url}
|
43
|
+
short_url = Shortener::ShortenedUrl.generate!(url)
|
44
|
+
File.join(@base_url, short_url.unique_key)
|
45
|
+
else
|
46
|
+
url
|
47
|
+
end
|
48
|
+
rescue => err
|
49
|
+
raise err if Rails.env.test?
|
50
|
+
Airbrake.notify(err, :url => url) if defined?(Airbrake)
|
51
|
+
return url
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.infer_base_url
|
55
|
+
host = ActionMailer::Base.default_url_options[:host]
|
56
|
+
if host.blank?
|
57
|
+
raise "Please supply :base_url for ShortenUrlInterceptor or define default_url_options for mailer"
|
58
|
+
else
|
59
|
+
"http://#{host}/"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/shortener/version.rb
CHANGED
@@ -1,19 +1,40 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
+
shared_examples_for "good code" do
|
5
|
+
it "redirects to actual url" do
|
6
|
+
get :show, :id => code
|
7
|
+
response.should redirect_to("http://www.doorkeeperhq.com/")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples_for "wrong code" do
|
12
|
+
it "redirects to actual url" do
|
13
|
+
get :show, :id => code
|
14
|
+
response.should redirect_to("/")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
4
18
|
describe Shortener::ShortenedUrlsController do
|
5
19
|
let(:short_url) { Shortener::ShortenedUrl.generate("www.doorkeeperhq.com") }
|
6
20
|
|
7
|
-
describe "GET show with
|
8
|
-
|
9
|
-
|
10
|
-
response.should redirect_to("http://www.doorkeeperhq.com/")
|
11
|
-
end
|
21
|
+
describe "GET show with actual code" do
|
22
|
+
let(:code) { short_url.unique_key}
|
23
|
+
it_should_behave_like "good code"
|
12
24
|
end
|
25
|
+
|
26
|
+
describe "GET show with good code but trailing characters" do
|
27
|
+
let(:code) { "#{short_url.unique_key}-" }
|
28
|
+
it_should_behave_like "good code"
|
29
|
+
end
|
30
|
+
|
13
31
|
describe "GET show with wrong code" do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
32
|
+
let(:code) { "testing" }
|
33
|
+
it_should_behave_like "wrong code"
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "GET show with code of invalid characters" do
|
37
|
+
let(:code) { "-" }
|
38
|
+
it_should_behave_like "wrong code"
|
18
39
|
end
|
19
40
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
require File.expand_path('../boot', __FILE__)
|
2
2
|
|
3
|
-
require "
|
4
|
-
require "active_record/railtie"
|
5
|
-
require "action_controller/railtie"
|
6
|
-
require "action_view/railtie"
|
7
|
-
|
3
|
+
require "rails/all"
|
8
4
|
Bundler.require
|
9
5
|
require "shortener"
|
10
6
|
|
@@ -40,5 +36,7 @@ module Dummy
|
|
40
36
|
|
41
37
|
# Configure sensitive parameters which will be filtered from the log file.
|
42
38
|
config.filter_parameters += [:password]
|
39
|
+
|
40
|
+
config.action_mailer.default_url_options = { :host => "mbln.jp" }
|
43
41
|
end
|
44
42
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'mail'
|
4
|
+
|
5
|
+
describe Shortener::ShortenUrlInterceptor do
|
6
|
+
|
7
|
+
def create_email(body)
|
8
|
+
Mail.new(:from => 'test@mbln.jp', :to => 'test@mbln.jp', :body => body).tap do |m|
|
9
|
+
m.encoded
|
10
|
+
Shortener::ShortenUrlInterceptor.new.delivering_email(m)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
TEXTS = [ "Test with URL: %{url}",
|
15
|
+
"Test with URL: %{url}!",
|
16
|
+
"Test with URL: %{url}, hu!",
|
17
|
+
"Test with URL: %{url}. hu!",
|
18
|
+
"Test with URL: <a href='%{url}'>test</a>",
|
19
|
+
"Test with URL: <a href=\"%{url}\">test</a>" ]
|
20
|
+
|
21
|
+
shared_examples_for "shortens URL in text" do |url|
|
22
|
+
TEXTS.each do |raw_email_body_text|
|
23
|
+
email_body_text = raw_email_body_text % {:url => url}
|
24
|
+
it("shortens for #{email_body_text}") do
|
25
|
+
email = create_email(email_body_text)
|
26
|
+
short_url = Shortener::ShortenedUrl.find_by_url(url)
|
27
|
+
short_url.should_not be_nil
|
28
|
+
email.body.should == (raw_email_body_text % {:url => "http://mbln.jp/#{short_url.unique_key}"})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
shared_examples_for "does not shorten URL" do |url|
|
34
|
+
TEXTS.each do |raw_email_body_text|
|
35
|
+
email_body_text = raw_email_body_text % {:url => url}
|
36
|
+
it("keeps URL for #{email_body_text}") do
|
37
|
+
email = create_email(email_body_text)
|
38
|
+
short_url = Shortener::ShortenedUrl.find_by_url(url)
|
39
|
+
short_url.should be_nil
|
40
|
+
email.body.should == email_body_text
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
[ "http://client.doorkeeper.jp/events/124-title",
|
46
|
+
"http://client.doorkeeper.jp/events/124-",
|
47
|
+
"http://client.doorkeeper.jp/events/124-title?auth_token=xabagangs",
|
48
|
+
"http://client.doorkeeper.jp/events/124-%E4%F6%A0",
|
49
|
+
].each do |url|
|
50
|
+
it_should_behave_like "shortens URL in text", url
|
51
|
+
end
|
52
|
+
|
53
|
+
# we won't shorten certain URLs:
|
54
|
+
[ "http://t.co/asdvk", # short URL
|
55
|
+
"http://twitter.com/doorkeeper_app", # twitter URL
|
56
|
+
"http://facebook.com/doorkeeper_app", # facebook URL
|
57
|
+
"http://d1dqic1fklzs1z.cloudfront.net/assets/doorkeeper_group_normal-3a3292fd09e39a70084c247aef60cba9.gif" # asset URL
|
58
|
+
].each do |url|
|
59
|
+
it_should_behave_like "does not shorten URL", url
|
60
|
+
end
|
61
|
+
|
62
|
+
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.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-04-
|
13
|
+
date: 2012-04-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
|
-
requirement: &
|
17
|
+
requirement: &70307977503340 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: 3.0.7
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70307977503340
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: sqlite3
|
28
|
-
requirement: &
|
28
|
+
requirement: &70307977519260 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70307977519260
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: rspec-rails
|
39
|
-
requirement: &
|
39
|
+
requirement: &70307977518620 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70307977518620
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: shoulda-matchers
|
50
|
-
requirement: &
|
50
|
+
requirement: &70307977517720 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70307977517720
|
59
59
|
description: Shortener is a Rails Engine Gem that makes it easy to create and interpret
|
60
60
|
shortened URLs on your own domain from within your Rails application. Once installed
|
61
61
|
Shortener will generate, store URLS and "unshorten" shortened URLs for your applications
|
@@ -82,6 +82,7 @@ files:
|
|
82
82
|
- lib/shortener/active_record_extension.rb
|
83
83
|
- lib/shortener/engine.rb
|
84
84
|
- lib/shortener/railtie.rb
|
85
|
+
- lib/shortener/shorten_url_interceptor.rb
|
85
86
|
- lib/shortener/version.rb
|
86
87
|
- shortener.gemspec
|
87
88
|
- spec/controllers/shortened_urls_controller_spec.rb
|
@@ -113,6 +114,7 @@ files:
|
|
113
114
|
- spec/dummy/script/rails
|
114
115
|
- spec/helpers/shortener_helper_spec.rb
|
115
116
|
- spec/models/shortened_url_spec.rb
|
117
|
+
- spec/shortener/shorten_url_interceptor_spec.rb
|
116
118
|
- spec/spec_helper.rb
|
117
119
|
homepage: http://jamespmcgrath.com/projects/shortener
|
118
120
|
licenses: []
|
@@ -134,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
136
|
version: 1.3.6
|
135
137
|
requirements: []
|
136
138
|
rubyforge_project: shortener
|
137
|
-
rubygems_version: 1.8.
|
139
|
+
rubygems_version: 1.8.17
|
138
140
|
signing_key:
|
139
141
|
specification_version: 3
|
140
142
|
summary: Shortener is a Rails Engine that makes it easy to create shortened URLs for
|