firefly 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -52,6 +52,14 @@ Next you can start your web server. You may try thin:
52
52
 
53
53
  Now visit `http://:hostname/` and enter your `:api_key`. Happy URL shortening!
54
54
 
55
+ # Enabling QR Codes
56
+
57
+ To enable QR Codes install the `barby` and `png` gems:
58
+
59
+ gem install barby png
60
+
61
+ Firefly will detect you have these gems available and enable QR Code support automatically.
62
+
55
63
  # Configuration
56
64
 
57
65
  All configuration is done in `config.ru`.
@@ -115,6 +123,11 @@ Feel free to fork Firefly and create patches for it. Here are some basic instruc
115
123
  [7]: http://help.github.com/forking/
116
124
  [8]: http://github.com/ariejan/firefly/issues
117
125
 
126
+ # Contributors
127
+
128
+ * Ariejan de Vroom - Original author
129
+ * Matthew Boeh - Contributor
130
+
118
131
  # License
119
132
 
120
133
  Copyright (c) 2009 Ariejan de Vroom
data/Rakefile CHANGED
@@ -18,8 +18,6 @@ begin
18
18
  gemspec.add_dependency('dm-aggregates', '~> 1.0.2')
19
19
  gemspec.add_dependency('dm-sqlite-adapter', '~> 1.0.2')
20
20
  gemspec.add_dependency('haml', '~> 3.0.18')
21
- gemspec.add_dependency('barby', '~> 0.4.0')
22
- gemspec.add_dependency('png', '1.1.0')
23
21
 
24
22
  gemspec.add_development_dependency('rspec', '~> 1.3.0')
25
23
  gemspec.add_development_dependency('rack-test', '~> 0.5.4')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{firefly}
8
- s.version = "1.1.0"
8
+ s.version = "1.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ariejan de Vroom"]
12
- s.date = %q{2010-10-02}
12
+ s.date = %q{2011-01-26}
13
13
  s.description = %q{FireFly is a simple URL shortner for personal use. It's powered by Sinatra and can be run with any Rack-capable web server.}
14
14
  s.email = %q{ariejan@ariejan.net}
15
15
  s.extra_rdoc_files = [
@@ -76,8 +76,6 @@ Gem::Specification.new do |s|
76
76
  s.add_runtime_dependency(%q<dm-aggregates>, ["~> 1.0.2"])
77
77
  s.add_runtime_dependency(%q<dm-sqlite-adapter>, ["~> 1.0.2"])
78
78
  s.add_runtime_dependency(%q<haml>, ["~> 3.0.18"])
79
- s.add_runtime_dependency(%q<barby>, ["~> 0.4.0"])
80
- s.add_runtime_dependency(%q<png>, ["= 1.1.0"])
81
79
  s.add_development_dependency(%q<rspec>, ["~> 1.3.0"])
82
80
  s.add_development_dependency(%q<rack-test>, ["~> 0.5.4"])
83
81
  else
@@ -88,8 +86,6 @@ Gem::Specification.new do |s|
88
86
  s.add_dependency(%q<dm-aggregates>, ["~> 1.0.2"])
89
87
  s.add_dependency(%q<dm-sqlite-adapter>, ["~> 1.0.2"])
90
88
  s.add_dependency(%q<haml>, ["~> 3.0.18"])
91
- s.add_dependency(%q<barby>, ["~> 0.4.0"])
92
- s.add_dependency(%q<png>, ["= 1.1.0"])
93
89
  s.add_dependency(%q<rspec>, ["~> 1.3.0"])
94
90
  s.add_dependency(%q<rack-test>, ["~> 0.5.4"])
95
91
  end
@@ -101,8 +97,6 @@ Gem::Specification.new do |s|
101
97
  s.add_dependency(%q<dm-aggregates>, ["~> 1.0.2"])
102
98
  s.add_dependency(%q<dm-sqlite-adapter>, ["~> 1.0.2"])
103
99
  s.add_dependency(%q<haml>, ["~> 3.0.18"])
104
- s.add_dependency(%q<barby>, ["~> 0.4.0"])
105
- s.add_dependency(%q<png>, ["= 1.1.0"])
106
100
  s.add_dependency(%q<rspec>, ["~> 1.3.0"])
107
101
  s.add_dependency(%q<rack-test>, ["~> 0.5.4"])
108
102
  end
@@ -7,8 +7,12 @@ require 'dm-core'
7
7
  require 'dm-migrations'
8
8
  require 'dm-transactions'
9
9
  require 'dm-aggregates'
10
- require 'barby'
11
- require 'barby/outputter/png_outputter'
10
+ begin
11
+ require 'barby'
12
+ require 'barby/outputter/png_outputter'
13
+ rescue LoadError
14
+
15
+ end
12
16
 
13
17
  $:.unshift(File.dirname(__FILE__)) unless
14
18
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
@@ -50,11 +50,11 @@ module Firefly
50
50
  "http://#{config[:hostname]}/#{url.code}"
51
51
  end
52
52
 
53
- def generate_short_url(url = nil)
53
+ def generate_short_url(url = nil, requested_code = nil)
54
54
  code, result = nil, nil
55
55
 
56
56
  if !url.nil? && url != ""
57
- ff_url = Firefly::Url.shorten(url)
57
+ ff_url = Firefly::Url.shorten(url, requested_code)
58
58
  if !ff_url.nil?
59
59
  code = ff_url.code
60
60
  result = "http://#{config[:hostname]}/#{code}"
@@ -115,8 +115,10 @@ module Firefly
115
115
  api_add = lambda {
116
116
  validate_api_permission or return "Permission denied: Invalid API key"
117
117
 
118
- @url = params[:url]
119
- @code, @result = generate_short_url(@url)
118
+ @url = params[:url]
119
+ @requested_code = params[:short]
120
+ @code, @result = generate_short_url(@url, @requested_code)
121
+ invalid = @result =~ /you posted is invalid/
120
122
  @result ||= "Invalid URL specified."
121
123
 
122
124
  if params[:visual]
@@ -124,6 +126,7 @@ module Firefly
124
126
  @code ||= "error"
125
127
  redirect "/?highlight=#{@code}"
126
128
  else
129
+ head 422 if invalid
127
130
  @result
128
131
  end
129
132
  }
@@ -214,20 +217,23 @@ module Firefly
214
217
  YAML::dump(output)
215
218
  end
216
219
 
217
- # GET /b3d.png
218
- #
219
- # Return a QR code image
220
- get '/:code.png' do
221
- @url = Firefly::Url.first(:code => params[:code])
220
+
221
+ if defined? Barby
222
+ # GET /b3d.png
223
+ #
224
+ # Return a QR code image
225
+ get '/:code.png' do
226
+ @url = Firefly::Url.first(:code => params[:code])
222
227
 
223
- if @url.nil?
224
- status 404
225
- "Sorry, that code is unknown."
226
- else
227
- qr = Barby::QrCode.new(short_url(@url))
228
- content_type('image/png')
229
- cache_control :public, :max_age => 2592000 # One month
230
- body(qr.to_png(:xdim => 15, :margin => 30))
228
+ if @url.nil?
229
+ status 404
230
+ "Sorry, that code is unknown."
231
+ else
232
+ qr = Barby::QrCode.new(short_url(@url))
233
+ content_type('image/png')
234
+ cache_control :public, :max_age => 2592000 # One month
235
+ body(qr.to_png(:xdim => 15, :margin => 30))
236
+ end
231
237
  end
232
238
  end
233
239
 
@@ -2,11 +2,12 @@ module Firefly
2
2
  class Url
3
3
  include DataMapper::Resource
4
4
 
5
- VALID_URL_REGEX = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
6
-
5
+ VALID_URL_REGEX = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
6
+ VALID_CODE_REGEX = /^[a-z0-9\-_]{3,64}$/i
7
+
7
8
  property :id, Serial
8
9
  property :url, String, :index => true, :length => 255
9
- property :code, String, :index => true, :length => 16
10
+ property :code, String, :index => true, :length => 64
10
11
  property :clicks, Integer, :default => 0
11
12
  property :created_at, DateTime, :default => Proc.new{Time.now}
12
13
 
@@ -16,13 +17,15 @@ module Firefly
16
17
  end
17
18
 
18
19
  # Shorten a long_url and return a new FireFly::Url
19
- def self.shorten(long_url)
20
+ def self.shorten(long_url, code = nil)
20
21
  return nil unless valid_url?(long_url)
21
-
22
+ return nil unless valid_code?(code)
23
+
22
24
  long_url = normalize_url(long_url)
23
25
 
24
26
  the_url = Firefly::Url.first(:url => long_url) || Firefly::Url.create(:url => long_url)
25
- the_url.update(:code => Firefly::Base62.encode(the_url.id.to_i)) if the_url.code.nil?
27
+ code ||= Firefly::Base62.encode(the_url.id.to_i)
28
+ the_url.update(:code => code) if the_url.code.nil?
26
29
  the_url
27
30
  end
28
31
 
@@ -36,5 +39,11 @@ module Firefly
36
39
  def self.valid_url?(url)
37
40
  url.match(Firefly::Url::VALID_URL_REGEX)
38
41
  end
42
+
43
+ def self.valid_code?(code)
44
+ return true if code.nil?
45
+ code.match(Firefly::Url::VALID_CODE_REGEX) && Firefly::Url.count(:code => code) == 0
46
+ end
47
+
39
48
  end
40
49
  end
@@ -21,6 +21,27 @@ describe "API" do
21
21
  last_response.body.should eql("http://test.host/#{url.code}")
22
22
  end
23
23
 
24
+ it "should permit including a requested short code" do
25
+ self.send verb, '/api/add', :url => "http://example.org", :short => 'orz', :api_key => 'test'
26
+
27
+ last_response.should be_ok
28
+ last_response.body.should eql("http://test.host/orz")
29
+ end
30
+
31
+ it "should not permit too-short, too-long, or duplicate short codes" do
32
+ self.send verb, '/api/add', :url => "http://example.org", :short => 'orz', :api_key => 'test'
33
+ last_response.should be_ok
34
+ self.send verb, '/api/add', :url => "http://example.com", :short => 'orz', :api_key => 'test'
35
+ last_response.should_not be_ok
36
+ last_response.body.should match("The URL you posted is invalid")
37
+ self.send verb, '/api/add', :url => "http://example.org", :short => 'or', :api_key => 'test'
38
+ last_response.should_not be_ok
39
+ last_response.body.should match("The URL you posted is invalid")
40
+ self.send verb, '/api/add', :url => "http://example.org", :short => 'orz' * 37, :api_key => 'test'
41
+ last_response.should_not be_ok
42
+ last_response.body.should match("The URL you posted is invalid")
43
+ end
44
+
24
45
  it "should show an error when shortening an invalid URL" do
25
46
  self.send verb, '/api/add', :url => 'ftp://example.org', :api_key => 'test'
26
47
 
@@ -14,24 +14,27 @@ describe "Firefly" do
14
14
  end
15
15
  end
16
16
 
17
- describe "QR Codes" do
18
- before(:each) do
19
- @url = Firefly::Url.create(:url => 'http://example.com/123', :code => 'alpha')
20
- end
21
17
 
22
- it "should return a 200 status" do
23
- get '/alpha.png'
24
- last_response.should be_ok
25
- end
18
+ if defined? Barby
19
+ describe "QR Codes" do
20
+ before(:each) do
21
+ @url = Firefly::Url.create(:url => 'http://example.com/123', :code => 'alpha')
22
+ end
26
23
 
27
- it "should return a PNG image" do
28
- get '/alpha.png'
29
- last_response.headers['Content-Type'].should eql('image/png')
30
- end
24
+ it "should return a 200 status" do
25
+ get '/alpha.png'
26
+ last_response.should be_ok
27
+ end
28
+
29
+ it "should return a PNG image" do
30
+ get '/alpha.png'
31
+ last_response.headers['Content-Type'].should eql('image/png')
32
+ end
31
33
 
32
- it "should cache-control to 1 month" do
33
- get '/alpha.png'
34
- last_response.headers['Cache-Control'].should eql('public, max-age=2592000')
34
+ it "should cache-control to 1 month" do
35
+ get '/alpha.png'
36
+ last_response.headers['Cache-Control'].should eql('public, max-age=2592000')
37
+ end
35
38
  end
36
39
  end
37
40
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: firefly
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 1.1.0
10
+ version: 1.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ariejan de Vroom
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-02 00:00:00 +02:00
18
+ date: 2011-01-26 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -129,42 +129,10 @@ dependencies:
129
129
  version: 3.0.18
130
130
  type: :runtime
131
131
  version_requirements: *id007
132
- - !ruby/object:Gem::Dependency
133
- name: barby
134
- prerelease: false
135
- requirement: &id008 !ruby/object:Gem::Requirement
136
- none: false
137
- requirements:
138
- - - ~>
139
- - !ruby/object:Gem::Version
140
- hash: 15
141
- segments:
142
- - 0
143
- - 4
144
- - 0
145
- version: 0.4.0
146
- type: :runtime
147
- version_requirements: *id008
148
- - !ruby/object:Gem::Dependency
149
- name: png
150
- prerelease: false
151
- requirement: &id009 !ruby/object:Gem::Requirement
152
- none: false
153
- requirements:
154
- - - "="
155
- - !ruby/object:Gem::Version
156
- hash: 19
157
- segments:
158
- - 1
159
- - 1
160
- - 0
161
- version: 1.1.0
162
- type: :runtime
163
- version_requirements: *id009
164
132
  - !ruby/object:Gem::Dependency
165
133
  name: rspec
166
134
  prerelease: false
167
- requirement: &id010 !ruby/object:Gem::Requirement
135
+ requirement: &id008 !ruby/object:Gem::Requirement
168
136
  none: false
169
137
  requirements:
170
138
  - - ~>
@@ -176,11 +144,11 @@ dependencies:
176
144
  - 0
177
145
  version: 1.3.0
178
146
  type: :development
179
- version_requirements: *id010
147
+ version_requirements: *id008
180
148
  - !ruby/object:Gem::Dependency
181
149
  name: rack-test
182
150
  prerelease: false
183
- requirement: &id011 !ruby/object:Gem::Requirement
151
+ requirement: &id009 !ruby/object:Gem::Requirement
184
152
  none: false
185
153
  requirements:
186
154
  - - ~>
@@ -192,7 +160,7 @@ dependencies:
192
160
  - 4
193
161
  version: 0.5.4
194
162
  type: :development
195
- version_requirements: *id011
163
+ version_requirements: *id009
196
164
  description: FireFly is a simple URL shortner for personal use. It's powered by Sinatra and can be run with any Rack-capable web server.
197
165
  email: ariejan@ariejan.net
198
166
  executables: []