firefly 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|