firefly 0.4.4 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/HISTORY +6 -0
- data/README.md +18 -13
- data/VERSION +1 -1
- data/firefly.gemspec +6 -2
- data/lib/firefly.rb +2 -0
- data/lib/firefly/server.rb +73 -2
- data/public/style.css +4 -1
- data/spec/files/export.csv +3 -0
- data/spec/files/export.xml +16 -0
- data/spec/files/export.yml +13 -0
- data/spec/firefly/api_spec.rb +37 -1
- data/spec/fixtures/urls.yml +11 -0
- data/spec/spec_helper.rb +14 -1
- data/views/index.haml +20 -6
- data/views/layout.haml +1 -1
- metadata +8 -4
data/.gitignore
CHANGED
data/HISTORY
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
= HEAD
|
2
|
+
|
3
|
+
* 2010-08-10 - Added sorting of shortened URLs. Closes #12.
|
4
|
+
* 2010-08-10 - Added CSV, XML and YAML export of all shortened URLs. Closes #11.
|
5
|
+
* 2010-08-10 - Updated bookmarklet JavaScript to escape URL-unsafe charachters in the API key. Fixes #17
|
6
|
+
|
1
7
|
= 0.4.4 / 2010-06-20
|
2
8
|
|
3
9
|
* 2010-06-20 - Updated gem dependencies for DataMapper 1.0.0
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# FireFly
|
2
2
|
|
3
|
-
FireFly is a simple URL shortener for personal use.
|
3
|
+
FireFly is a simple URL shortener for personal (or not so personal) use.
|
4
|
+
|
5
|
+
# Quick-Start (2 minutes) with Heroku
|
6
|
+
|
7
|
+
See the [screencast][1] or [written instructions][2] on how to setup Firefly within 2 minutes on [Heroku][3]
|
4
8
|
|
5
9
|
# Installation
|
6
10
|
|
@@ -54,14 +58,12 @@ All configuration is done in `config.ru`.
|
|
54
58
|
|
55
59
|
* `:hostname` sets the hostname to use for shortened URLs.
|
56
60
|
* `:api_key` sets the API key. This key is required when posting new URLs
|
57
|
-
* `:database` a database URI that [DataMapper][
|
61
|
+
* `:database` a database URI that [DataMapper][4] can understand.
|
58
62
|
* `:recent_urls` sets the number of URLs to show in the overview. Default: 25.
|
59
63
|
* `:tweet` set the template to use for tweets. Default: `"Check this out: %short_url%"`
|
60
64
|
|
61
65
|
It's possible to use all kinds of backends with DataMapper. Sqlite3 and MySQL have been tested, but others may work as well.
|
62
66
|
|
63
|
-
[1]: http://datamapper.org/
|
64
|
-
|
65
67
|
# Usage
|
66
68
|
|
67
69
|
Simply visit `http://:hostname/` and enter your `:api_key`. You can now shorten URLs.
|
@@ -93,22 +95,25 @@ After you restart Terminal.app (or at least reload the `.profile` file) you can
|
|
93
95
|
|
94
96
|
# Bugs, Feature Requests, etc.
|
95
97
|
|
96
|
-
* [Source][
|
97
|
-
* [Issue tracker][
|
98
|
-
|
99
|
-
[2]: http://github.com/ariejan/firefly
|
100
|
-
[3]: http://github.com/ariejan/firefly/issues
|
98
|
+
* [Source][5]
|
99
|
+
* [Issue tracker][6]
|
101
100
|
|
102
101
|
Feel free to fork Firefly and create patches for it. Here are some basic instructions:
|
103
102
|
|
104
|
-
* [Fork][
|
103
|
+
* [Fork][7] Firefly
|
105
104
|
* Create a topic branch - `git checkout -b my_branch`
|
106
105
|
* Push to your branch - `git push origin my_branch`
|
107
|
-
* Create an [Issue][
|
106
|
+
* Create an [Issue][8] with a link to your branch
|
108
107
|
* That's it!
|
109
108
|
|
110
|
-
[
|
111
|
-
[
|
109
|
+
[1]: http://ariejan.net/2010/07/12/screencast-firefly-url-shortener-in-less-than-25-minutes/
|
110
|
+
[2]: http://ariejan.net/2010/06/06/setup-your-own-firefly-url-shortener-in-25-minutes/
|
111
|
+
[3]: http://heroku.com
|
112
|
+
[4]: http://datamapper.org/
|
113
|
+
[5]: http://github.com/ariejan/firefly
|
114
|
+
[6]: http://github.com/ariejan/firefly/issues
|
115
|
+
[7]: http://help.github.com/forking/
|
116
|
+
[8]: http://github.com/ariejan/firefly/issues
|
112
117
|
|
113
118
|
# License
|
114
119
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.5
|
data/firefly.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{firefly}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.5"
|
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-
|
12
|
+
s.date = %q{2010-08-10}
|
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 = [
|
@@ -36,10 +36,14 @@ Gem::Specification.new do |s|
|
|
36
36
|
"public/jquery-1.4.2.min.js",
|
37
37
|
"public/reset.css",
|
38
38
|
"public/style.css",
|
39
|
+
"spec/files/export.csv",
|
40
|
+
"spec/files/export.xml",
|
41
|
+
"spec/files/export.yml",
|
39
42
|
"spec/firefly/api_spec.rb",
|
40
43
|
"spec/firefly/base62_spec.rb",
|
41
44
|
"spec/firefly/server_spec.rb",
|
42
45
|
"spec/firefly/url_spec.rb",
|
46
|
+
"spec/fixtures/urls.yml",
|
43
47
|
"spec/spec.opts",
|
44
48
|
"spec/spec_helper.rb",
|
45
49
|
"views/index.haml",
|
data/lib/firefly.rb
CHANGED
data/lib/firefly/server.rb
CHANGED
@@ -94,7 +94,12 @@ module Firefly
|
|
94
94
|
get '/' do
|
95
95
|
@highlight = Firefly::Url.first(:code => params[:highlight])
|
96
96
|
@error = params[:highlight] == "error"
|
97
|
-
|
97
|
+
|
98
|
+
sort_column = params[:s] || 'created_at'
|
99
|
+
sort_order = params[:d] || 'desc'
|
100
|
+
|
101
|
+
@urls = Firefly::Url.all(:limit => config[:recent_urls], :order => [ sort_column.to_sym.send(sort_order.to_sym) ] )
|
102
|
+
|
98
103
|
haml :index
|
99
104
|
end
|
100
105
|
|
@@ -142,7 +147,73 @@ module Firefly
|
|
142
147
|
haml :info
|
143
148
|
end
|
144
149
|
end
|
145
|
-
|
150
|
+
|
151
|
+
# GET /api/export.csv
|
152
|
+
#
|
153
|
+
# Download a CSV file with all shortened URLs
|
154
|
+
get '/api/export.csv' do
|
155
|
+
validate_api_permission or return "Permission denied: Invalid API key"
|
156
|
+
|
157
|
+
@urls = Firefly::Url.all(:order => [ :created_at.asc ])
|
158
|
+
|
159
|
+
output = "\"Code\",\"Short URL\",\"Long URL\",\"Clicks\",\"Created at\"\n"
|
160
|
+
@urls.each do |url|
|
161
|
+
output += "\"#{url.code}\",\"#{short_url(url)}\",\"#{url.url}\",\"#{url.clicks}\",\"#{url.created_at.strftime('%Y-%m-%d %H:%M:%S')}\"\n"
|
162
|
+
end
|
163
|
+
|
164
|
+
attachment "firefly-export.csv"
|
165
|
+
content_type "text/csv"
|
166
|
+
output
|
167
|
+
end
|
168
|
+
|
169
|
+
# GET /api/export.xml
|
170
|
+
#
|
171
|
+
# Download a XML file with all shortened URLs
|
172
|
+
get '/api/export.xml' do
|
173
|
+
validate_api_permission or return "Permission denied: Invalid API key"
|
174
|
+
|
175
|
+
@urls = Firefly::Url.all(:order => [ :created_at.asc ])
|
176
|
+
|
177
|
+
# I know, manual XML creation is ugly, at least you don't need nokogiri
|
178
|
+
output = "<urls>\n"
|
179
|
+
@urls.each do |url|
|
180
|
+
output += " <url>\n"
|
181
|
+
output += " <code>#{url.code}</code>\n"
|
182
|
+
output += " <short_url>#{short_url(url)}</short_url>\n"
|
183
|
+
output += " <long_url>#{url.url}</long_url>\n"
|
184
|
+
output += " <clicks>#{url.clicks}</clicks>\n"
|
185
|
+
output += " <created_at>#{url.created_at.strftime('%Y-%m-%d %H:%M:%S')}</created_at>\n"
|
186
|
+
output += " </url>\n"
|
187
|
+
end
|
188
|
+
output += "</urls>\n"
|
189
|
+
|
190
|
+
attachment "firefly-export.xml"
|
191
|
+
content_type "text/xml"
|
192
|
+
output
|
193
|
+
end
|
194
|
+
|
195
|
+
# GET /api/export.yml
|
196
|
+
#
|
197
|
+
# Download a YAML file with all shortened URLs
|
198
|
+
get '/api/export.yml' do
|
199
|
+
validate_api_permission or return "Permission denied: Invalid API key"
|
200
|
+
|
201
|
+
@urls = Firefly::Url.all(:order => [ :created_at.asc ])
|
202
|
+
|
203
|
+
output = {}
|
204
|
+
@urls.each do |url|
|
205
|
+
output[url.code] = { 'code' => url.code,
|
206
|
+
'short_url' => short_url(url),
|
207
|
+
'long_url' => url.url,
|
208
|
+
'clicks' => url.clicks,
|
209
|
+
'created_at' => url.created_at.strftime('%Y-%m-%d %H:%M:%S') }
|
210
|
+
end
|
211
|
+
|
212
|
+
attachment "firefly-export.yml"
|
213
|
+
content_type "text/yaml"
|
214
|
+
YAML::dump(output)
|
215
|
+
end
|
216
|
+
|
146
217
|
# GET /b3d
|
147
218
|
#
|
148
219
|
# Redirect to the shortened URL
|
data/public/style.css
CHANGED
@@ -87,5 +87,8 @@ body { padding:0; margin:0; }
|
|
87
87
|
#main table tr td.value.fill { width: 100%; white-space: normal; }
|
88
88
|
#main table tr td.value.center { text-align: center; }
|
89
89
|
#main table tr td.label { font-weight: bold; }
|
90
|
+
#main table tr td.label a { text-decoration: none; font-size: 11px; }
|
91
|
+
#main table tr td.label a.highlight { color: #f00; }
|
92
|
+
|
90
93
|
#main table tr td input.short_url { border: 1px solid #CCC; color: #666; font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 11px; height: 16px; padding: 3px 5px 2px; width: 160px; }
|
91
|
-
#main table tr td img.twitter { border: 0; margin: 0; padding: 0; float: right; width: 16px; height: 16px; }
|
94
|
+
#main table tr td img.twitter { border: 0; margin: 0; padding: 0; float: right; width: 16px; height: 16px; }
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<urls>
|
2
|
+
<url>
|
3
|
+
<code>def</code>
|
4
|
+
<short_url>http://test.host/def</short_url>
|
5
|
+
<long_url>http://example.org/</long_url>
|
6
|
+
<clicks>456</clicks>
|
7
|
+
<created_at>2010-02-24 14:55:00</created_at>
|
8
|
+
</url>
|
9
|
+
<url>
|
10
|
+
<code>abc</code>
|
11
|
+
<short_url>http://test.host/abc</short_url>
|
12
|
+
<long_url>http://example.com/</long_url>
|
13
|
+
<clicks>123</clicks>
|
14
|
+
<created_at>2010-04-01 12:00:00</created_at>
|
15
|
+
</url>
|
16
|
+
</urls>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
---
|
2
|
+
abc:
|
3
|
+
created_at: 2010-04-01 12:00:00
|
4
|
+
long_url: http://example.com/
|
5
|
+
short_url: http://test.host/abc
|
6
|
+
code: abc
|
7
|
+
clicks: 123
|
8
|
+
def:
|
9
|
+
created_at: 2010-02-24 14:55:00
|
10
|
+
long_url: http://example.org/
|
11
|
+
short_url: http://test.host/def
|
12
|
+
code: def
|
13
|
+
clicks: 456
|
data/spec/firefly/api_spec.rb
CHANGED
@@ -69,7 +69,7 @@ describe "API" do
|
|
69
69
|
|
70
70
|
it "should create a new Firefly::Url" do
|
71
71
|
lambda {
|
72
|
-
self.send verb, '/api/add', :url => 'http://example.org', :api_key => 'test'
|
72
|
+
self.send verb, '/api/add', :url => 'http://example.org/', :api_key => 'test'
|
73
73
|
}.should change(Firefly::Url, :count).by(1)
|
74
74
|
end
|
75
75
|
|
@@ -119,4 +119,40 @@ describe "API" do
|
|
119
119
|
last_response.status.should be(401)
|
120
120
|
end
|
121
121
|
end
|
122
|
+
|
123
|
+
describe "exports" do
|
124
|
+
before(:each) do
|
125
|
+
load_fixtures
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should export in CSV" do
|
129
|
+
get '/api/export.csv', :api_key => "test"
|
130
|
+
last_response.body.should eql(spec_file('export.csv'))
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should export in XML" do
|
134
|
+
get '/api/export.xml', :api_key => "test"
|
135
|
+
last_response.body.should eql(spec_file('export.xml'))
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should export in YAML" do
|
139
|
+
get '/api/export.yml', :api_key => "test"
|
140
|
+
last_response.body.should eql(spec_file('export.yml'))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "api key" do
|
145
|
+
def app
|
146
|
+
Firefly::Server.new do
|
147
|
+
set :hostname, "test.host"
|
148
|
+
set :api_key, "test#!"
|
149
|
+
set :database, "sqlite3://#{Dir.pwd}/firefly_test.sqlite3"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should be okay adding a new URL" do
|
154
|
+
self.send :get, '/api/add', :url => 'http://example.org/api_key_test', :api_key => 'test#!'
|
155
|
+
last_response.should be_ok
|
156
|
+
end
|
157
|
+
end
|
122
158
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,6 +6,7 @@ require 'rack/test'
|
|
6
6
|
require 'spec'
|
7
7
|
require 'spec/autorun'
|
8
8
|
require 'spec/interop/test'
|
9
|
+
require 'yaml'
|
9
10
|
|
10
11
|
# set test environment
|
11
12
|
set :environment, :test
|
@@ -37,4 +38,16 @@ Spec::Runner.configure do |config|
|
|
37
38
|
r.adapter.push_transaction(transaction)
|
38
39
|
end
|
39
40
|
end
|
40
|
-
|
41
|
+
|
42
|
+
# Loads the urls.yml fixtures.
|
43
|
+
def load_fixtures
|
44
|
+
Firefly::Url.destroy
|
45
|
+
urls = YAML::load(File.open('spec/fixtures/urls.yml'))
|
46
|
+
urls.each { |key, url| Firefly::Url.create(url) }
|
47
|
+
end
|
48
|
+
|
49
|
+
# Load a spec file and return its contents
|
50
|
+
def spec_file(filename)
|
51
|
+
File.open('spec/files/'+filename) { |f| f.read }
|
52
|
+
end
|
53
|
+
end
|
data/views/index.haml
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
%p
|
7
7
|
Drag the following link to your bookmarks. Click it to shorten the URL to the page you're currently viewing.
|
8
8
|
%p
|
9
|
-
%a{ :href => "javascript:var%20d=document,w=window,enc=encodeURIComponent,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),s2=((s.toString()=='')?s:('%22'+enc(s)+'%22')),f='http://#{@config[:hostname]}/api/add',l=d.location,p='?visual=1&api_key
|
9
|
+
%a{ :href => "javascript:var%20d=document,w=window,enc=encodeURIComponent,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),s2=((s.toString()=='')?s:('%22'+enc(s)+'%22')),key=enc('#{@config[:api_key]}'),f='http://#{@config[:hostname]}/api/add',l=d.location,p='?visual=1&api_key='+key+'&url='+enc(l.href),u=f+p;try{if(!/^(.*\.)?tumblrzzz[^.]*$/.test(l.host))throw(0);tstbklt();}catch(z){a%20=function(){if(!w.open(u))l.href=u;};if(/Firefox/.test(navigator.userAgent))setTimeout(a,0);else%20a();}void(0)" } Shorten with #{@config[:hostname]}
|
10
10
|
|
11
11
|
%h1 How about shortening a URL?
|
12
12
|
|
@@ -23,6 +23,8 @@
|
|
23
23
|
|
24
24
|
%p
|
25
25
|
The URL you posted is invalid. Please post a valid HTTP url, including the protocol (http://) prefix.
|
26
|
+
|
27
|
+
%p= @url
|
26
28
|
|
27
29
|
- if @highlight
|
28
30
|
%h2 Your short URL
|
@@ -48,10 +50,10 @@
|
|
48
50
|
|
49
51
|
%table
|
50
52
|
%tr
|
51
|
-
%td.label Short URL
|
52
|
-
%td.label Full URL
|
53
|
-
%td.label Clicks
|
54
|
-
%td.label Shortened
|
53
|
+
%td.label(nowrap='nowrap') Short URL <a href="/?s=code&d=asc">▲</a> <a href="/?s=code&d=desc">▼</a>
|
54
|
+
%td.label(nowrap='nowrap') Full URL <a href="/?s=url&d=asc">▲</a> <a href="/?s=url&d=desc">▼</a>
|
55
|
+
%td.label(nowrap='nowrap') Clicks <a href="/?s=clicks&d=asc">▲</a> <a href="/?s=clicks&d=desc">▼</a>
|
56
|
+
%td.label(nowrap='nowrap') Shortened At <a href="/?s=created_at&d=asc">▲</a> <a href="/?s=created_at&d=desc">▼</a>
|
55
57
|
%td.label
|
56
58
|
- @urls.each do |url|
|
57
59
|
%tr{ :class => is_highlighted?(url) ? 'highlighted' : '' }
|
@@ -69,6 +71,18 @@
|
|
69
71
|
$('input.short_url').each(function(index) {
|
70
72
|
$(this).mouseup(function() { $(this).select(); });
|
71
73
|
});
|
74
|
+
|
75
|
+
if (window.location.search == "") {
|
76
|
+
var pathname = window.location.pathname + '?s=created_at&d=desc';
|
77
|
+
} else {
|
78
|
+
var pathname = window.location.pathname + window.location.search;
|
79
|
+
}
|
80
|
+
|
81
|
+
$('#main table tr td.label a').each(function(index) {
|
82
|
+
if ($(this).attr('href') == pathname) {
|
83
|
+
$(this).addClass('highlight');
|
84
|
+
}
|
85
|
+
});
|
72
86
|
});
|
73
87
|
- else
|
74
88
|
%h1 Please enter your API key
|
@@ -81,4 +95,4 @@
|
|
81
95
|
%label{ :for => 'api_key' } API Key
|
82
96
|
%input{ :type => 'password', :name => 'api_key', :id => 'api_key' }
|
83
97
|
%p
|
84
|
-
%input{ :type => 'submit', :name => 'submit', :id => 'submit', :value => "Let me in" }
|
98
|
+
%input{ :type => 'submit', :name => 'submit', :id => 'submit', :value => "Let me in" }
|
data/views/layout.haml
CHANGED
@@ -17,4 +17,4 @@
|
|
17
17
|
|
18
18
|
#footer
|
19
19
|
%p
|
20
|
-
Powered by <a href="http://github.com/ariejan/firefly">Firefly</a> v#{Firefly::Version} | <a href="http://github.com/ariejan/firefly/tree/v#{Firefly::Version}">Source</a> | <a href="http://github.com/ariejan/firefly/issues">Issues</a>
|
20
|
+
Powered by <a href="http://github.com/ariejan/firefly">Firefly</a> v#{Firefly::Version} | <a href="http://github.com/ariejan/firefly/tree/v#{Firefly::Version}">Source</a> | <a href="http://github.com/ariejan/firefly/issues">Issues</a> | Export <a href="/api/export.csv">CSV</a>, <a href="/api/export.yml">YAML</a> or <a href="/api/export.xml">XML</a>
|
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:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
9
|
+
- 5
|
10
|
+
version: 0.4.5
|
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-
|
18
|
+
date: 2010-08-10 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -190,10 +190,14 @@ files:
|
|
190
190
|
- public/jquery-1.4.2.min.js
|
191
191
|
- public/reset.css
|
192
192
|
- public/style.css
|
193
|
+
- spec/files/export.csv
|
194
|
+
- spec/files/export.xml
|
195
|
+
- spec/files/export.yml
|
193
196
|
- spec/firefly/api_spec.rb
|
194
197
|
- spec/firefly/base62_spec.rb
|
195
198
|
- spec/firefly/server_spec.rb
|
196
199
|
- spec/firefly/url_spec.rb
|
200
|
+
- spec/fixtures/urls.yml
|
197
201
|
- spec/spec.opts
|
198
202
|
- spec/spec_helper.rb
|
199
203
|
- views/index.haml
|