firefly 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +4 -0
- data/Gemfile.lock +53 -0
- data/HISTORY +15 -8
- data/README.md +23 -24
- data/Rakefile +3 -29
- data/config.ru.example +4 -4
- data/firefly.gemspec +24 -96
- data/firefly_test.sqlite3-journal +0 -0
- data/lib/firefly.rb +2 -1
- data/lib/firefly/code_factory.rb +23 -0
- data/lib/firefly/server.rb +77 -69
- data/lib/firefly/url.rb +25 -11
- data/lib/firefly/version.rb +2 -2
- data/public/style.css +3 -3
- data/spec/firefly/api_spec.rb +33 -33
- data/spec/firefly/base62_spec.rb +1 -1
- data/spec/firefly/code_factory_spec.rb +12 -0
- data/spec/firefly/server_spec.rb +11 -11
- data/spec/firefly/url_spec.rb +24 -12
- data/spec/spec_helper.rb +4 -1
- data/views/error.haml +11 -0
- data/views/index.haml +5 -14
- data/views/info.haml +3 -3
- data/views/layout.haml +4 -6
- metadata +23 -11
data/lib/firefly/server.rb
CHANGED
@@ -3,94 +3,100 @@ require 'haml'
|
|
3
3
|
require 'digest/md5'
|
4
4
|
|
5
5
|
module Firefly
|
6
|
+
class InvalidUrlError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
class InvalidCodeError < StandardError
|
10
|
+
end
|
11
|
+
|
6
12
|
class Server < Sinatra::Base
|
7
13
|
enable :sessions
|
8
|
-
|
14
|
+
|
9
15
|
dir = File.join(File.dirname(__FILE__), '..', '..')
|
10
16
|
|
11
17
|
set :views, "#{dir}/views"
|
12
18
|
set :public, "#{dir}/public"
|
13
19
|
set :haml, {:format => :html5 }
|
14
20
|
set :static, true
|
15
|
-
|
21
|
+
|
16
22
|
attr_accessor :config
|
17
|
-
|
23
|
+
|
18
24
|
helpers do
|
19
25
|
include Rack::Utils
|
20
26
|
alias_method :h, :escape_html
|
21
|
-
|
27
|
+
|
22
28
|
def url(*path_parts)
|
23
29
|
[ path_prefix, path_parts ].join("/").squeeze('/')
|
24
30
|
end
|
25
31
|
alias_method :u, :url
|
26
|
-
|
32
|
+
|
27
33
|
def path_prefix
|
28
34
|
request.env['SCRIPT_NAME']
|
29
35
|
end
|
30
|
-
|
36
|
+
|
31
37
|
def set_api_cookie(key)
|
32
38
|
session["firefly_session"] = Digest::MD5.hexdigest(key)
|
33
39
|
end
|
34
|
-
|
40
|
+
|
35
41
|
def has_valid_api_cookie?
|
36
42
|
key = session["firefly_session"]
|
37
43
|
key == Digest::MD5.hexdigest(config[:api_key])
|
38
44
|
end
|
39
|
-
|
45
|
+
|
40
46
|
def validate_api_permission
|
41
47
|
if !has_valid_api_cookie? && params[:api_key] != config[:api_key]
|
42
48
|
status 401
|
43
49
|
return false
|
44
|
-
|
45
|
-
|
50
|
+
else
|
51
|
+
return true
|
46
52
|
end
|
47
53
|
end
|
48
|
-
|
54
|
+
|
49
55
|
def short_url(url)
|
50
56
|
"http://#{config[:hostname]}/#{url.code}"
|
51
57
|
end
|
52
|
-
|
58
|
+
|
53
59
|
def generate_short_url(url = nil, requested_code = nil)
|
54
60
|
code, result = nil, nil
|
55
61
|
|
56
|
-
|
62
|
+
begin
|
57
63
|
ff_url = Firefly::Url.shorten(url, requested_code)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
64
|
+
code, result = ff_url.code, "http://#{config[:hostname]}/#{ff_url.code}"
|
65
|
+
rescue Firefly::InvalidUrlError
|
66
|
+
code, result = nil, "ERROR: The URL you posted is invalid."
|
67
|
+
rescue Firefly::InvalidCodeError
|
68
|
+
code, result = nil, "ERROR: The code is invalid or already exists."
|
69
|
+
rescue
|
70
|
+
code, result = nil, "ERROR: An unknown error occured"
|
65
71
|
end
|
66
|
-
|
72
|
+
|
67
73
|
return code, result
|
68
74
|
end
|
69
|
-
|
75
|
+
|
70
76
|
def is_highlighted?(url)
|
71
77
|
return false unless @highlight
|
72
78
|
@highlight == url.code
|
73
79
|
end
|
74
|
-
|
80
|
+
|
75
81
|
# Format a tweet
|
76
82
|
def tweet(url)
|
77
83
|
config[:tweet].gsub('%short_url%', url)
|
78
84
|
end
|
79
|
-
|
85
|
+
|
80
86
|
def store_api_key(key)
|
81
87
|
if key == config[:api_key]
|
82
88
|
set_api_cookie(config[:api_key])
|
83
89
|
end
|
84
90
|
end
|
85
91
|
end
|
86
|
-
|
92
|
+
|
87
93
|
before do
|
88
94
|
@authenticated = has_valid_api_cookie?
|
89
95
|
@config = config
|
90
96
|
@highlight = nil
|
91
|
-
@title = "Firefly
|
97
|
+
@title = "Firefly at http://#{@config[:hostname]}"
|
92
98
|
end
|
93
|
-
|
99
|
+
|
94
100
|
get '/' do
|
95
101
|
@highlight = Firefly::Url.first(:code => params[:highlight])
|
96
102
|
@error = params[:highlight] == "error"
|
@@ -102,12 +108,12 @@ module Firefly
|
|
102
108
|
|
103
109
|
haml :index
|
104
110
|
end
|
105
|
-
|
111
|
+
|
106
112
|
post '/api/set' do
|
107
113
|
store_api_key(params[:api_key])
|
108
114
|
redirect '/'
|
109
115
|
end
|
110
|
-
|
116
|
+
|
111
117
|
# GET /add?url=http://ariejan.net&api_key=test
|
112
118
|
# POST /add?url=http://ariejan.net&api_key=test
|
113
119
|
#
|
@@ -117,23 +123,21 @@ module Firefly
|
|
117
123
|
|
118
124
|
@url = params[:url]
|
119
125
|
@requested_code = params[:short]
|
120
|
-
@code, @result
|
121
|
-
invalid = @
|
122
|
-
|
123
|
-
|
126
|
+
@code, @result = generate_short_url(@url, @requested_code)
|
127
|
+
invalid = @code.nil?
|
128
|
+
|
124
129
|
if params[:visual]
|
125
130
|
store_api_key(params[:api_key])
|
126
|
-
@code
|
127
|
-
redirect "/?highlight=#{@code}"
|
131
|
+
@code.nil? ? haml(:error) : redirect("/?highlight=#{@code}")
|
128
132
|
else
|
129
133
|
head 422 if invalid
|
130
134
|
@result
|
131
135
|
end
|
132
136
|
}
|
133
|
-
|
137
|
+
|
134
138
|
get '/api/add', &api_add
|
135
139
|
post '/api/add', &api_add
|
136
|
-
|
140
|
+
|
137
141
|
# GET /b3d+
|
138
142
|
#
|
139
143
|
# Show info on the URL
|
@@ -141,7 +145,7 @@ module Firefly
|
|
141
145
|
validate_api_permission or return "Permission denied: Invalid API key"
|
142
146
|
|
143
147
|
@url = Firefly::Url.first(:code => params[:code])
|
144
|
-
|
148
|
+
|
145
149
|
if @url.nil?
|
146
150
|
status 404
|
147
151
|
"Sorry, that code is unknown."
|
@@ -150,7 +154,7 @@ module Firefly
|
|
150
154
|
haml :info
|
151
155
|
end
|
152
156
|
end
|
153
|
-
|
157
|
+
|
154
158
|
# GET /api/export.csv
|
155
159
|
#
|
156
160
|
# Download a CSV file with all shortened URLs
|
@@ -217,7 +221,6 @@ module Firefly
|
|
217
221
|
YAML::dump(output)
|
218
222
|
end
|
219
223
|
|
220
|
-
|
221
224
|
if defined? Barby
|
222
225
|
# GET /b3d.png
|
223
226
|
#
|
@@ -251,49 +254,54 @@ module Firefly
|
|
251
254
|
redirect @url.url, 301
|
252
255
|
end
|
253
256
|
end
|
254
|
-
|
257
|
+
|
255
258
|
def initialize config = {}, &blk
|
256
259
|
super
|
257
260
|
@config = config.is_a?(Config) ? config : Firefly::Config.new(config)
|
258
261
|
@config.instance_eval(&blk) if block_given?
|
259
|
-
|
262
|
+
|
260
263
|
begin
|
261
264
|
DataMapper.setup(:default, @config[:database])
|
262
265
|
DataMapper.auto_upgrade!
|
263
266
|
check_mysql_collation
|
267
|
+
check_code_factory
|
264
268
|
rescue
|
265
269
|
puts "Error setting up database connection. Please check the `database` setting in config.ru"
|
266
|
-
|
267
|
-
|
268
|
-
|
270
|
+
puts $!
|
271
|
+
puts "-------"
|
272
|
+
puts $!.backtrace
|
269
273
|
exit(1)
|
270
274
|
end
|
271
275
|
end
|
272
276
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
277
|
+
def check_code_factory
|
278
|
+
Firefly::CodeFactory.first || Firefly::CodeFactory.create(:count => 0)
|
279
|
+
end
|
280
|
+
|
281
|
+
def check_mysql_collation(first_try = true)
|
282
|
+
# Make sure the 'code' column is case-sensitive. This hack is for
|
283
|
+
# MySQL only, other database systems don't have this problem.
|
284
|
+
if DataMapper.repository(:default).adapter =~ "DataMapper::Adapters::MysqlAdapter"
|
285
|
+
query = "SHOW FULL COLUMNS FROM firefly_urls WHERE Field='code';"
|
286
|
+
collation = DataMapper.repository(:default).adapter.select(query)[0][:collation]
|
287
|
+
|
288
|
+
if collation != "utf8_bin"
|
289
|
+
if first_try
|
290
|
+
puts " ~ Your MySQL database is not using the 'utf8-bin' collation. Trying to fix..."
|
291
|
+
DataMapper.repository(:default).adapter.execute("ALTER TABLE firefly_urls MODIFY `code` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;")
|
292
|
+
return check_mysql_collation(false)
|
293
|
+
else
|
294
|
+
puts " ~ Failed to set the collation for `code` in `firefly_urls`. Please see http://wiki.github.com/ariejan/firefly/faq for details."
|
295
|
+
return false
|
296
|
+
end
|
297
|
+
else
|
298
|
+
if !first_try
|
299
|
+
puts " ~ Successfully fixed your database."
|
300
|
+
end
|
301
|
+
return true
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
297
305
|
end
|
298
306
|
end
|
299
307
|
|
data/lib/firefly/url.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Firefly
|
2
2
|
class Url
|
3
3
|
include DataMapper::Resource
|
4
|
-
|
4
|
+
|
5
5
|
VALID_URL_REGEX = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/ix
|
6
6
|
VALID_CODE_REGEX = /^[a-z0-9\-_]{3,64}$/i
|
7
7
|
|
@@ -10,33 +10,47 @@ module Firefly
|
|
10
10
|
property :code, String, :index => true, :length => 64
|
11
11
|
property :clicks, Integer, :default => 0
|
12
12
|
property :created_at, DateTime, :default => Proc.new{Time.now}
|
13
|
-
|
13
|
+
|
14
14
|
# Increase the visits counter by 1
|
15
15
|
def register_click!
|
16
16
|
self.update(:clicks => self.clicks + 1)
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
# Shorten a long_url and return a new FireFly::Url
|
20
20
|
def self.shorten(long_url, code = nil)
|
21
21
|
code = nil if code !~ /\S/
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
raise Firefly::InvalidUrlError.new unless valid_url?(long_url)
|
24
|
+
raise Firefly::InvalidCodeError.new unless valid_code?(code)
|
25
25
|
|
26
26
|
long_url = normalize_url(long_url)
|
27
|
-
|
27
|
+
|
28
28
|
the_url = Firefly::Url.first(:url => long_url) || Firefly::Url.create(:url => long_url)
|
29
|
-
|
30
|
-
|
29
|
+
return the_url unless the_url.code.nil?
|
30
|
+
|
31
|
+
code ||= get_me_a_code
|
32
|
+
the_url.update(:code => code)
|
31
33
|
the_url
|
32
|
-
end
|
33
|
-
|
34
|
+
end
|
35
|
+
|
34
36
|
private
|
37
|
+
|
38
|
+
# Generate a unique code, not already in use.
|
39
|
+
def self.get_me_a_code
|
40
|
+
code = Firefly::CodeFactory.next_code!
|
41
|
+
|
42
|
+
if Firefly::Url.count(:code => code) > 0
|
43
|
+
code = get_me_a_code
|
44
|
+
end
|
45
|
+
|
46
|
+
code
|
47
|
+
end
|
48
|
+
|
35
49
|
# Normalize the URL
|
36
50
|
def self.normalize_url(url)
|
37
51
|
URI.parse(URI.escape(url)).normalize.to_s
|
38
52
|
end
|
39
|
-
|
53
|
+
|
40
54
|
# Validates the URL to be a valid http or https one.
|
41
55
|
def self.valid_url?(url)
|
42
56
|
url.match(Firefly::Url::VALID_URL_REGEX)
|
data/lib/firefly/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Firefly
|
2
|
-
|
3
|
-
end
|
2
|
+
VERSION = "1.3.0"
|
3
|
+
end
|
data/public/style.css
CHANGED
@@ -2,7 +2,7 @@ html { background:#efefef; font-family:Arial, Verdana, sans-serif; font-size:13p
|
|
2
2
|
body { padding:0; margin:0; }
|
3
3
|
|
4
4
|
.header { background:#000; padding:8px 5% 0 5%; border-bottom:1px solid #444;border-bottom:5px solid #ce1212;}
|
5
|
-
.header h1 { color:#
|
5
|
+
.header h1 { color:#e0e0e0; font-size:140%; font-weight:bold; margin-bottom:12px; margin-top:6px;}
|
6
6
|
.header ul li { display:inline;}
|
7
7
|
.header ul li a { color:#fff; text-decoration:none; margin-right:10px; display:inline-block; padding:8px; -webkit-border-top-right-radius:6px; -webkit-border-top-left-radius:6px; -moz-border-radius-topleft:6px; -moz-border-radius-topright:6px; }
|
8
8
|
.header ul li a:hover { background:#333;}
|
@@ -58,7 +58,7 @@ body { padding:0; margin:0; }
|
|
58
58
|
#footer { padding:10px 5%; background:#efefef; color:#999; font-size:85%; line-height:1.5; border-top:5px solid #ccc; padding-top:10px;}
|
59
59
|
#footer p a { color:#999;}
|
60
60
|
|
61
|
-
#main
|
61
|
+
#main blockquote { background: #efefef; color: #999; line-height: 1.5; margin: 10px; padding: 10px; }
|
62
62
|
|
63
63
|
#main ul.failed {}
|
64
64
|
#main ul.failed li {background:-webkit-gradient(linear, left top, left bottom, from(#efefef), to(#fff)) #efefef; margin-top:10px; padding:10px; overflow:hidden; -webkit-border-radius:5px; border:1px solid #ccc; }
|
@@ -90,5 +90,5 @@ body { padding:0; margin:0; }
|
|
90
90
|
#main table tr td.label a { text-decoration: none; font-size: 11px; }
|
91
91
|
#main table tr td.label a.highlight { color: #f00; }
|
92
92
|
|
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:
|
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: 200px; }
|
94
94
|
#main table tr td img.twitter { border: 0; margin: 0; padding: 0; float: right; width: 16px; height: 16px; }
|
data/spec/firefly/api_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe "API" do
|
|
6
6
|
def app
|
7
7
|
@@app
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
[:post, :get].each do |verb|
|
11
11
|
describe "adding a URL by #{verb.to_s.upcase}" do
|
12
12
|
it "should be okay adding a new URL" do
|
@@ -31,58 +31,58 @@ describe "API" do
|
|
31
31
|
|
32
32
|
it "should permit including a requested short code" do
|
33
33
|
self.send verb, '/api/add', :url => "http://example.org", :short => 'orz', :api_key => 'test'
|
34
|
-
|
34
|
+
|
35
35
|
last_response.should be_ok
|
36
36
|
last_response.body.should eql("http://test.host/orz")
|
37
37
|
end
|
38
38
|
|
39
|
-
it "should not
|
39
|
+
it "should not allow the same short code twice" do
|
40
40
|
self.send verb, '/api/add', :url => "http://example.org", :short => 'orz', :api_key => 'test'
|
41
41
|
last_response.should be_ok
|
42
42
|
self.send verb, '/api/add', :url => "http://example.com", :short => 'orz', :api_key => 'test'
|
43
43
|
last_response.should_not be_ok
|
44
|
-
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not allow short codes of size < 3" do
|
45
47
|
self.send verb, '/api/add', :url => "http://example.org", :short => 'or', :api_key => 'test'
|
46
48
|
last_response.should_not be_ok
|
47
|
-
|
48
|
-
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not allow short codes of size > 64" do
|
52
|
+
self.send verb, '/api/add', :url => "http://example.org", :short => 'x' * 65, :api_key => 'test'
|
49
53
|
last_response.should_not be_ok
|
50
|
-
last_response.body.should match("The URL you posted is invalid")
|
51
54
|
end
|
52
55
|
|
53
56
|
it "should show an error when shortening an invalid URL" do
|
54
57
|
self.send verb, '/api/add', :url => 'ftp://example.org', :api_key => 'test'
|
55
|
-
|
56
58
|
last_response.body.should match("The URL you posted is invalid")
|
57
59
|
end
|
58
|
-
|
60
|
+
|
59
61
|
it "should show an error when shortening an invalid URL in visual mode" do
|
60
62
|
self.send verb, '/api/add', :url => 'ftp://example.org', :api_key => 'test', :visual => "1"
|
61
|
-
follow_redirect!
|
62
|
-
|
63
63
|
last_response.body.should match("The URL you posted is invalid")
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
it "should redirect to the highlighted URL when visual is enabled" do
|
67
67
|
self.send verb, '/api/add', :url => 'http://example.org/', :api_key => 'test', :visual => "1"
|
68
68
|
follow_redirect!
|
69
|
-
|
69
|
+
|
70
70
|
last_request.path.should eql("/")
|
71
71
|
last_request.should be_get
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
it "should store the API key in the session with visual enabled" do
|
75
75
|
self.send verb, '/api/add', :url => 'http://example.org/', :api_key => 'test', :visual => "1"
|
76
|
-
follow_redirect!
|
77
|
-
|
76
|
+
follow_redirect!
|
77
|
+
|
78
78
|
last_response.body.should_not match(/API Key/)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
it "should highlight the shortened URL" do
|
82
82
|
self.send verb, '/api/add', :url => 'http://example.org/', :api_key => 'test', :visual => "1"
|
83
83
|
url = Firefly::Url.first(:url => "http://example.org/")
|
84
|
-
follow_redirect!
|
85
|
-
|
84
|
+
follow_redirect!
|
85
|
+
|
86
86
|
last_request.query_string.should match(/highlight=#{url.code}/)
|
87
87
|
end
|
88
88
|
|
@@ -91,10 +91,10 @@ describe "API" do
|
|
91
91
|
last_response.status.should eql(401)
|
92
92
|
end
|
93
93
|
|
94
|
-
|
94
|
+
it "should not return a shortened URL on 401" do
|
95
95
|
self.send verb, '/api/add', :url => 'http://example.org', :api_key => 'false'
|
96
|
-
|
97
|
-
|
96
|
+
last_response.body.should match(/Permission denied: Invalid API key/)
|
97
|
+
end
|
98
98
|
|
99
99
|
it "should create a new Firefly::Url" do
|
100
100
|
lambda {
|
@@ -107,42 +107,42 @@ describe "API" do
|
|
107
107
|
|
108
108
|
lambda {
|
109
109
|
self.send verb, '/api/add', :url => 'http://example.org', :api_key => 'test'
|
110
|
-
}.should_not change(Firefly::Url, :count).by(1)
|
110
|
+
}.should_not change(Firefly::Url, :count).by(1)
|
111
111
|
end
|
112
112
|
end
|
113
|
-
end
|
114
|
-
|
113
|
+
end
|
114
|
+
|
115
115
|
describe "getting information" do
|
116
116
|
before(:each) do
|
117
117
|
@created_at = Time.now
|
118
118
|
@url = Firefly::Url.create(:url => 'http://example.com/123', :code => 'alpha', :clicks => 69, :created_at => @created_at)
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
it "should work" do
|
122
122
|
get '/api/info/alpha', :api_key => "test"
|
123
123
|
last_response.should be_ok
|
124
124
|
end
|
125
|
-
|
125
|
+
|
126
126
|
it "should show the click count" do
|
127
127
|
get '/api/info/alpha', :api_key => "test"
|
128
128
|
last_response.body.should match(/69/)
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
131
|
it "should show the short URL" do
|
132
132
|
get '/api/info/alpha', :api_key => "test"
|
133
133
|
last_response.body.should match(/alpha/)
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
it "should show the shortened at time" do
|
137
137
|
get '/api/info/alpha', :api_key => "test"
|
138
138
|
last_response.body.should match(/#{@created_at.strftime("%Y-%m-%d %H:%M")}/)
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
it "should show the full URL" do
|
142
142
|
get '/api/info/alpha', :api_key => "test"
|
143
143
|
last_response.body.should match(/http:\/\/example.com\/123/)
|
144
144
|
end
|
145
|
-
|
145
|
+
|
146
146
|
it "should validate API permissions" do
|
147
147
|
get '/api/info/alpha', :api_key => false
|
148
148
|
last_response.status.should be(401)
|
@@ -175,10 +175,10 @@ describe "API" do
|
|
175
175
|
Firefly::Server.new do
|
176
176
|
set :hostname, "test.host"
|
177
177
|
set :api_key, "test#!"
|
178
|
-
set :database, "
|
178
|
+
set :database, "mysql://root@localhost/firefly_test"
|
179
179
|
end
|
180
180
|
end
|
181
|
-
|
181
|
+
|
182
182
|
it "should be okay adding a new URL" do
|
183
183
|
self.send :get, '/api/add', :url => 'http://example.org/api_key_test', :api_key => 'test#!'
|
184
184
|
last_response.should be_ok
|