dragonfly 1.1.3 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dragonfly might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.travis.yml +12 -5
- data/History.md +330 -305
- data/README.md +5 -2
- data/dev/rails_template.rb +35 -33
- data/dragonfly.gemspec +10 -16
- data/lib/dragonfly.rb +3 -1
- data/lib/dragonfly/content.rb +4 -4
- data/lib/dragonfly/job/fetch_url.rb +2 -2
- data/lib/dragonfly/model/class_methods.rb +7 -2
- data/lib/dragonfly/routed_endpoint.rb +2 -2
- data/lib/dragonfly/server.rb +2 -2
- data/lib/dragonfly/shell.rb +19 -13
- data/lib/dragonfly/url_mapper.rb +5 -5
- data/lib/dragonfly/utils.rb +1 -1
- data/lib/dragonfly/version.rb +1 -1
- data/lib/rails/generators/dragonfly/templates/initializer.rb.erb +3 -3
- data/samples/white pixel.png b/data/samples/mevs' white → pixel.png +0 -0
- data/spec/dragonfly/content_spec.rb +3 -3
- data/spec/dragonfly/cookie_monster_spec.rb +2 -2
- data/spec/dragonfly/image_magick/plugin_spec.rb +1 -1
- data/spec/dragonfly/image_magick/processors/convert_spec.rb +3 -3
- data/spec/dragonfly/job/fetch_url_spec.rb +13 -0
- data/spec/dragonfly/model/active_record_spec.rb +62 -0
- data/spec/dragonfly/shell_spec.rb +12 -10
- data/spec/dragonfly_spec.rb +37 -13
- metadata +38 -8
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
Dragonfly
|
2
2
|
===========
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/markevans/dragonfly.svg?branch=master)](https://travis-ci.org/markevans/dragonfly)
|
5
|
+
|
3
6
|
Hello!!
|
4
7
|
Dragonfly is a highly customizable ruby gem for handling images and other attachments and is already in use on thousands of websites.
|
5
8
|
|
@@ -10,7 +13,7 @@ class User < ActiveRecord::Base # model
|
|
10
13
|
end
|
11
14
|
```
|
12
15
|
```erb
|
13
|
-
<%= image_tag @user.photo.thumb('300x200#').url
|
16
|
+
<%= image_tag @user.photo.thumb('300x200#').url if @user.photo_stored? # view %>
|
14
17
|
```
|
15
18
|
|
16
19
|
... or generate text images on-demand in Sinatra ...
|
@@ -44,7 +47,7 @@ Installation
|
|
44
47
|
|
45
48
|
or in your Gemfile
|
46
49
|
```ruby
|
47
|
-
gem 'dragonfly', '~> 1.
|
50
|
+
gem 'dragonfly', '~> 1.2.2'
|
48
51
|
```
|
49
52
|
|
50
53
|
Require with
|
data/dev/rails_template.rb
CHANGED
@@ -1,40 +1,42 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
generate "
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
app.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
after_bundle do
|
2
|
+
gem 'dragonfly', :path => File.expand_path('../..', __FILE__)
|
3
|
+
generate "dragonfly"
|
4
|
+
generate "scaffold", "photo image_uid:string image_name:string"
|
5
|
+
rake "db:migrate"
|
6
|
+
route %(
|
7
|
+
get "text/:text" => Dragonfly.app.endpoint { |params, app|
|
8
|
+
app.generate(:text, params[:text])
|
9
|
+
}
|
10
|
+
)
|
11
|
+
route "root :to => 'photos#index'"
|
12
|
+
run "rm -rf public/index.html"
|
12
13
|
|
13
|
-
possible_base_classes = ['ActiveRecord::Base', 'ApplicationRecord']
|
14
|
-
possible_base_classes.each do |base_class|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
possible_base_classes = ['ActiveRecord::Base', 'ApplicationRecord']
|
15
|
+
possible_base_classes.each do |base_class|
|
16
|
+
inject_into_file 'app/models/photo.rb', :after => "class Photo < #{base_class}\n" do
|
17
|
+
%(
|
18
|
+
attr_accessible :image rescue nil
|
19
|
+
dragonfly_accessor :image
|
20
|
+
)
|
21
|
+
end
|
20
22
|
end
|
21
|
-
end
|
22
23
|
|
23
|
-
gsub_file 'app/views/photos/_form.html.erb', /^.*:image_.*$/, ''
|
24
|
+
gsub_file 'app/views/photos/_form.html.erb', /^.*:image_.*$/, ''
|
24
25
|
|
25
|
-
inject_into_file 'app/views/photos/_form.html.erb', :before => %(<div class="actions">\n) do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
inject_into_file 'app/views/photos/_form.html.erb', :before => %(<div class="actions">\n) do
|
27
|
+
%(
|
28
|
+
<div class="field">
|
29
|
+
<%= form.label :image %><br>
|
30
|
+
<%= form.file_field :image %>
|
31
|
+
</div>
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
end
|
33
|
+
<%= image_tag @photo.image.thumb('100x100').url if @photo.image_stored? %>
|
34
|
+
)
|
35
|
+
end
|
35
36
|
|
36
|
-
gsub_file "app/controllers/photos_controller.rb", "permit(", "permit(:image, "
|
37
|
+
gsub_file "app/controllers/photos_controller.rb", "permit(", "permit(:image, "
|
37
38
|
|
38
|
-
append_file 'app/views/photos/show.html.erb', %(
|
39
|
-
|
40
|
-
)
|
39
|
+
append_file 'app/views/photos/show.html.erb', %(
|
40
|
+
<%= image_tag @photo.image.thumb('300x300').url if @photo.image_stored? %>
|
41
|
+
)
|
42
|
+
end
|
data/dragonfly.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "dragonfly/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "dragonfly"
|
@@ -13,33 +13,27 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "http://github.com/markevans/dragonfly"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.files = `git ls-files`.split($/)
|
16
|
-
spec.executables
|
17
|
-
spec.test_files
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
spec.extra_rdoc_files = [
|
20
20
|
"LICENSE",
|
21
|
-
"README.md"
|
21
|
+
"README.md",
|
22
22
|
]
|
23
23
|
|
24
|
-
# Rack 2.0 only works with ruby >= 2.2.2
|
25
|
-
if RUBY_VERSION < "2.2.2"
|
26
|
-
rack_version = "~> 1.3"
|
27
|
-
activemodel_version = "~> 4.2"
|
28
|
-
else
|
29
|
-
rack_version = ">= 1.3"
|
30
|
-
activemodel_version = nil
|
31
|
-
end
|
32
|
-
|
33
24
|
# Runtime dependencies
|
34
|
-
spec.add_runtime_dependency("rack",
|
25
|
+
spec.add_runtime_dependency("rack", ">= 1.3")
|
35
26
|
spec.add_runtime_dependency("multi_json", "~> 1.0")
|
36
27
|
spec.add_runtime_dependency("addressable", "~> 2.3")
|
37
28
|
|
38
29
|
# Development dependencies
|
39
30
|
spec.add_development_dependency("rspec", "~> 2.5")
|
40
31
|
spec.add_development_dependency("webmock")
|
41
|
-
spec.add_development_dependency("activemodel"
|
32
|
+
spec.add_development_dependency("activemodel")
|
42
33
|
if RUBY_PLATFORM == "java"
|
43
34
|
spec.add_development_dependency("jruby-openssl")
|
35
|
+
else
|
36
|
+
spec.add_development_dependency("activerecord")
|
37
|
+
spec.add_development_dependency("sqlite3")
|
44
38
|
end
|
45
39
|
end
|
data/lib/dragonfly.rb
CHANGED
@@ -33,12 +33,14 @@ module Dragonfly
|
|
33
33
|
|
34
34
|
# Logging
|
35
35
|
def logger
|
36
|
-
@logger
|
36
|
+
@logger = Logger.new('dragonfly.log') unless instance_variable_defined?(:@logger)
|
37
|
+
@logger
|
37
38
|
end
|
38
39
|
attr_writer :logger
|
39
40
|
|
40
41
|
[:debug, :warn, :info].each do |method|
|
41
42
|
define_method method do |message|
|
43
|
+
return unless logger
|
42
44
|
logger.send(method, "DRAGONFLY: #{message}")
|
43
45
|
end
|
44
46
|
end
|
data/lib/dragonfly/content.rb
CHANGED
@@ -137,7 +137,7 @@ module Dragonfly
|
|
137
137
|
# # ===> "beach.jpg: image/jpeg"
|
138
138
|
def shell_eval(opts={})
|
139
139
|
should_escape = opts[:escape] != false
|
140
|
-
command = yield(should_escape ? shell.
|
140
|
+
command = yield(should_escape ? shell.escape(path) : path)
|
141
141
|
run command, :escape => should_escape
|
142
142
|
end
|
143
143
|
|
@@ -152,7 +152,7 @@ module Dragonfly
|
|
152
152
|
ext = opts[:ext] || self.ext
|
153
153
|
should_escape = opts[:escape] != false
|
154
154
|
tempfile = Utils.new_tempfile(ext)
|
155
|
-
new_path = should_escape ? shell.
|
155
|
+
new_path = should_escape ? shell.escape(tempfile.path) : tempfile.path
|
156
156
|
command = yield(new_path)
|
157
157
|
run(command, :escape => should_escape)
|
158
158
|
update(tempfile)
|
@@ -169,8 +169,8 @@ module Dragonfly
|
|
169
169
|
ext = opts[:ext] || self.ext
|
170
170
|
should_escape = opts[:escape] != false
|
171
171
|
tempfile = Utils.new_tempfile(ext)
|
172
|
-
old_path = should_escape ? shell.
|
173
|
-
new_path = should_escape ? shell.
|
172
|
+
old_path = should_escape ? shell.escape(path) : path
|
173
|
+
new_path = should_escape ? shell.escape(tempfile.path) : tempfile.path
|
174
174
|
command = yield(old_path, new_path)
|
175
175
|
run(command, :escape => should_escape)
|
176
176
|
update(tempfile)
|
@@ -80,7 +80,7 @@ module Dragonfly
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def update_from_data_uri
|
83
|
-
mime_type, b64_data = uri.scan(/\Adata:([^;]+);base64,(.*)
|
83
|
+
mime_type, b64_data = uri.scan(/\Adata:([^;]+);base64,(.*)\Z/m)[0]
|
84
84
|
if mime_type && b64_data
|
85
85
|
data = Base64.decode64(b64_data)
|
86
86
|
ext = app.ext_for(mime_type)
|
@@ -91,7 +91,7 @@ module Dragonfly
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def parse_url(url)
|
94
|
-
URI.parse(url)
|
94
|
+
URI.parse(url.to_s)
|
95
95
|
rescue URI::InvalidURIError
|
96
96
|
begin
|
97
97
|
encoded_uri = Addressable::URI.parse(url).normalize.to_s
|
@@ -30,7 +30,12 @@ module Dragonfly
|
|
30
30
|
|
31
31
|
# Add callbacks
|
32
32
|
before_save :save_dragonfly_attachments if respond_to?(:before_save)
|
33
|
-
|
33
|
+
case
|
34
|
+
when respond_to?(:after_commit)
|
35
|
+
after_commit :destroy_dragonfly_attachments, on: :destroy
|
36
|
+
when respond_to?(:after_destroy)
|
37
|
+
after_destroy :destroy_dragonfly_attachments
|
38
|
+
end
|
34
39
|
|
35
40
|
# Register the new attribute
|
36
41
|
dragonfly_attachment_classes << new_dragonfly_attachment_class(attribute, app, config_block)
|
@@ -86,7 +91,7 @@ module Dragonfly
|
|
86
91
|
unless Utils.blank?(string)
|
87
92
|
begin
|
88
93
|
dragonfly_attachments[attribute].retained_attrs = Serializer.json_b64_decode(string)
|
89
|
-
rescue Serializer::BadString
|
94
|
+
rescue Serializer::BadString
|
90
95
|
Dragonfly.warn("couldn't update attachment with serialized retained_#{attribute} string #{string.inspect}")
|
91
96
|
end
|
92
97
|
end
|
@@ -24,9 +24,9 @@ module Dragonfly
|
|
24
24
|
Dragonfly.warn("can't handle return value from routed endpoint: #{value.inspect}")
|
25
25
|
plain_response(500, "Server Error")
|
26
26
|
end
|
27
|
-
rescue Job::NoSHAGiven
|
27
|
+
rescue Job::NoSHAGiven
|
28
28
|
plain_response(400, "You need to give a SHA parameter")
|
29
|
-
rescue Job::IncorrectSHA
|
29
|
+
rescue Job::IncorrectSHA
|
30
30
|
plain_response(400, "The SHA parameter you gave is incorrect")
|
31
31
|
end
|
32
32
|
|
data/lib/dragonfly/server.rb
CHANGED
@@ -28,11 +28,11 @@ module Dragonfly
|
|
28
28
|
attr_reader :url_format, :fetch_file_whitelist, :fetch_url_whitelist
|
29
29
|
|
30
30
|
def add_to_fetch_file_whitelist(patterns)
|
31
|
-
fetch_file_whitelist.push
|
31
|
+
fetch_file_whitelist.push(*patterns)
|
32
32
|
end
|
33
33
|
|
34
34
|
def add_to_fetch_url_whitelist(patterns)
|
35
|
-
fetch_url_whitelist.push
|
35
|
+
fetch_url_whitelist.push(*patterns)
|
36
36
|
end
|
37
37
|
|
38
38
|
def url_format=(url_format)
|
data/lib/dragonfly/shell.rb
CHANGED
@@ -15,14 +15,11 @@ module Dragonfly
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def escape_args(args)
|
18
|
-
args.shellsplit.map
|
19
|
-
quote arg.gsub(/\\?'/, %q('\\\\''))
|
20
|
-
end.join(' ')
|
18
|
+
args.shellsplit.map{|arg| escape(arg) }.join(' ')
|
21
19
|
end
|
22
20
|
|
23
|
-
def
|
24
|
-
|
25
|
-
q + string + q
|
21
|
+
def escape(string)
|
22
|
+
Shellwords.escape(string)
|
26
23
|
end
|
27
24
|
|
28
25
|
private
|
@@ -36,22 +33,31 @@ module Dragonfly
|
|
36
33
|
def run_command(command)
|
37
34
|
result = `#{command}`
|
38
35
|
status = $?
|
39
|
-
|
36
|
+
raise_command_failed!(command, status.exitstatus) unless status.success?
|
40
37
|
result
|
38
|
+
rescue Errno::ENOENT => e
|
39
|
+
raise_command_failed!(command, nil, e.message)
|
41
40
|
end
|
42
41
|
|
43
42
|
else
|
44
43
|
|
45
44
|
def run_command(command)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
45
|
+
stdout_str, stderr_str, status = Open3.capture3(command)
|
46
|
+
raise_command_failed!(command, status.exitstatus, stderr_str) unless status.success?
|
47
|
+
stdout_str
|
48
|
+
rescue Errno::ENOENT => e
|
49
|
+
raise_command_failed!(command, nil, e.message)
|
52
50
|
end
|
53
51
|
|
54
52
|
end
|
55
53
|
|
54
|
+
def raise_command_failed!(command, status=nil, error=nil)
|
55
|
+
raise CommandFailed, [
|
56
|
+
"Command failed: #{command}",
|
57
|
+
("exit status: #{status}" if status),
|
58
|
+
("error: #{error}" if error),
|
59
|
+
].join(', ')
|
60
|
+
end
|
61
|
+
|
56
62
|
end
|
57
63
|
end
|
data/lib/dragonfly/url_mapper.rb
CHANGED
@@ -24,7 +24,7 @@ module Dragonfly
|
|
24
24
|
|
25
25
|
def initialize(url_format)
|
26
26
|
@url_format = url_format
|
27
|
-
raise BadUrlFormat, "bad url format #{url_format}" if url_format[/
|
27
|
+
raise BadUrlFormat, "bad url format #{url_format}" if url_format[/\w:\w/]
|
28
28
|
init_segments
|
29
29
|
init_url_regexp
|
30
30
|
end
|
@@ -43,7 +43,7 @@ module Dragonfly
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def params_in_url
|
46
|
-
@params_in_url ||= url_format.scan(
|
46
|
+
@params_in_url ||= url_format.scan(/\:\w+/).map{|f| f.tr(':','') }
|
47
47
|
end
|
48
48
|
|
49
49
|
def url_for(params)
|
@@ -51,7 +51,7 @@ module Dragonfly
|
|
51
51
|
url = url_format.dup
|
52
52
|
segments.each do |seg|
|
53
53
|
value = params[seg.param]
|
54
|
-
value ? url.sub!(
|
54
|
+
value ? url.sub!(/:\w+/, Utils.uri_escape_segment(value.to_s)) : url.sub!(/.:\w+/, '')
|
55
55
|
params.delete(seg.param)
|
56
56
|
end
|
57
57
|
url << "?#{Rack::Utils.build_query(params)}" if params.any?
|
@@ -62,7 +62,7 @@ module Dragonfly
|
|
62
62
|
|
63
63
|
def init_segments
|
64
64
|
@segments = []
|
65
|
-
url_format.scan(/([^\
|
65
|
+
url_format.scan(/([^\w]):(\w+)/).each do |seperator, param|
|
66
66
|
segments << Segment.new(
|
67
67
|
param,
|
68
68
|
seperator,
|
@@ -73,7 +73,7 @@ module Dragonfly
|
|
73
73
|
|
74
74
|
def init_url_regexp
|
75
75
|
i = -1
|
76
|
-
regexp_string = url_format.gsub(/[^\
|
76
|
+
regexp_string = url_format.gsub(/[^\w]:\w+/) do
|
77
77
|
i += 1
|
78
78
|
segments[i].regexp_string
|
79
79
|
end
|
data/lib/dragonfly/utils.rb
CHANGED
data/lib/dragonfly/version.rb
CHANGED
@@ -20,7 +20,7 @@ Dragonfly.logger = Rails.logger
|
|
20
20
|
Rails.application.middleware.use Dragonfly::Middleware
|
21
21
|
|
22
22
|
# Add model functionality
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
ActiveSupport.on_load(:active_record) do
|
24
|
+
extend Dragonfly::Model
|
25
|
+
extend Dragonfly::Model::Validations
|
26
26
|
end
|
File without changes
|
@@ -232,7 +232,7 @@ describe Dragonfly::Content do
|
|
232
232
|
path = p
|
233
233
|
"cat #{path}"
|
234
234
|
end.should == "big\nstuff"
|
235
|
-
path.should == app.shell.
|
235
|
+
path.should == app.shell.escape(content.path)
|
236
236
|
end
|
237
237
|
|
238
238
|
it "allows evaluating without escaping" do
|
@@ -253,8 +253,8 @@ describe Dragonfly::Content do
|
|
253
253
|
new_path = n
|
254
254
|
"cp #{o} #{n}"
|
255
255
|
end.should == content
|
256
|
-
old_path.should == app.shell.
|
257
|
-
new_path.should == app.shell.
|
256
|
+
old_path.should == app.shell.escape(original_path)
|
257
|
+
new_path.should == app.shell.escape(content.path)
|
258
258
|
content.data.should == "big\nstuff"
|
259
259
|
end
|
260
260
|
|
@@ -7,7 +7,7 @@ describe Dragonfly::CookieMonster do
|
|
7
7
|
def app(extra_env={})
|
8
8
|
Rack::Builder.new do
|
9
9
|
use Dragonfly::CookieMonster
|
10
|
-
run proc{|env| env.merge!(extra_env); [200, {"Set-Cookie" => "blah", "Something" => "else"}, ["body here"]] }
|
10
|
+
run proc{|env| env.merge!(extra_env); [200, {"Set-Cookie" => "blah=thing", "Something" => "else"}, ["body here"]] }
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -15,7 +15,7 @@ describe Dragonfly::CookieMonster do
|
|
15
15
|
response = Rack::MockRequest.new(app).get('')
|
16
16
|
response.status.should == 200
|
17
17
|
response.body.should == "body here"
|
18
|
-
response.headers["Set-Cookie"].should == "blah"
|
18
|
+
response.headers["Set-Cookie"].should == "blah=thing"
|
19
19
|
response.headers["Something"].should == "else"
|
20
20
|
end
|
21
21
|
|