file_column_with_s3 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -2
- data/lib/file_column.rb +56 -26
- data/lib/file_column_helper.rb +6 -11
- data/lib/magick_file_column.rb +2 -2
- data/s3_env.example +2 -2
- data/test/abstract_unit.rb +36 -0
- data/test/file_column_helper_test.rb +13 -3
- data/test/file_column_test.rb +52 -2
- data/test/magick_test.rb +0 -1
- metadata +47 -19
- data/lib/file_column/attachement_store.rb +0 -93
- data/test/attachement_store_test.rb +0 -96
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'bundler'
|
1
|
+
require 'bundler'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
4
|
task :default => [:test]
|
@@ -31,8 +31,8 @@ task :package => [:checkout_release, :release_docs] do
|
|
31
31
|
sh "cd release; tar czf #{PKG_NAME}-#{PKG_VERSION}.tar.gz #{PKG_NAME}-#{PKG_VERSION}"
|
32
32
|
end
|
33
33
|
|
34
|
+
desc "Run all tests"
|
34
35
|
task :test do
|
35
|
-
sh "cd test; ruby attachement_store_test.rb"
|
36
36
|
sh "cd test; ruby file_column_test.rb"
|
37
37
|
sh "cd test; ruby file_column_helper_test.rb"
|
38
38
|
sh "cd test; ruby magick_test.rb"
|
data/lib/file_column.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
require 'tempfile'
|
3
3
|
require 'magick_file_column'
|
4
|
-
require '
|
4
|
+
require 'storage'
|
5
5
|
|
6
6
|
module FileColumn # :nodoc:
|
7
7
|
def self.append_features(base)
|
@@ -18,20 +18,22 @@ module FileColumn # :nodoc:
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
def self.store(path_prefix, extra_opts={})
|
22
|
+
builder = @store_builder || Storage::Builder.new(:filesystem)
|
23
|
+
@build_opts ||= {}
|
24
|
+
builder.build(path_prefix, @build_opts.merge(extra_opts))
|
24
25
|
end
|
25
26
|
|
26
|
-
def self.
|
27
|
-
@
|
27
|
+
def self.config_store(type, build_opts={})
|
28
|
+
@build_opts = build_opts
|
29
|
+
@store_builder = Storage::Builder.new(type)
|
28
30
|
end
|
29
31
|
|
30
32
|
def self.init_options(defaults, model, attr)
|
31
33
|
options = defaults.dup
|
32
|
-
options[:store_dir] ||= File.join(
|
34
|
+
options[:store_dir] ||= File.join(model, attr)
|
33
35
|
unless options[:store_dir].is_a?(Symbol)
|
34
|
-
options[:tmp_base_dir] ||= File.join(options[:store_dir], "tmp")
|
36
|
+
options[:tmp_base_dir] ||= File.join(options[:root_path], options[:store_dir], "tmp")
|
35
37
|
end
|
36
38
|
options[:base_url] ||= options[:web_root] + File.join(model, attr)
|
37
39
|
|
@@ -51,6 +53,9 @@ module FileColumn # :nodoc:
|
|
51
53
|
@options_method = "#{attr}_options".to_sym
|
52
54
|
end
|
53
55
|
|
56
|
+
def store
|
57
|
+
nil
|
58
|
+
end
|
54
59
|
|
55
60
|
def assign(file)
|
56
61
|
if file.is_a? File
|
@@ -122,10 +127,7 @@ module FileColumn # :nodoc:
|
|
122
127
|
def store_dir
|
123
128
|
if options[:store_dir].is_a? Symbol
|
124
129
|
raise ArgumentError.new("'#{options[:store_dir]}' is not an instance method of class #{@instance.class.name}") unless @instance.respond_to?(options[:store_dir])
|
125
|
-
|
126
|
-
dir = File.join(options[:root_path], @instance.send(options[:store_dir]))
|
127
|
-
FileUtils.mkpath(dir) unless File.exists?(dir)
|
128
|
-
dir
|
130
|
+
@instance.send(options[:store_dir])
|
129
131
|
else
|
130
132
|
options[:store_dir]
|
131
133
|
end
|
@@ -135,7 +137,7 @@ module FileColumn # :nodoc:
|
|
135
137
|
if options[:tmp_base_dir]
|
136
138
|
options[:tmp_base_dir]
|
137
139
|
else
|
138
|
-
dir = File.join(store_dir, "tmp")
|
140
|
+
dir = File.join(options[:root_path], store_dir, "tmp")
|
139
141
|
FileUtils.mkpath(dir) unless File.exists?(dir)
|
140
142
|
dir
|
141
143
|
end
|
@@ -223,7 +225,8 @@ module FileColumn # :nodoc:
|
|
223
225
|
def store_upload(file)
|
224
226
|
@tmp_dir = FileColumn.generate_temp_name
|
225
227
|
@dir = File.join(tmp_base_dir, @tmp_dir)
|
226
|
-
|
228
|
+
|
229
|
+
FileUtils.mkdir_p(@dir)
|
227
230
|
|
228
231
|
@filename = FileColumn::sanitize_filename(file.original_filename)
|
229
232
|
local_file_path = File.join(tmp_base_dir,@tmp_dir,@filename)
|
@@ -356,22 +359,24 @@ module FileColumn # :nodoc:
|
|
356
359
|
class PermanentUploadedFile < RealUploadedFile # :nodoc:
|
357
360
|
def initialize(*args)
|
358
361
|
super *args
|
359
|
-
@store = FileColumn.store(store_dir)
|
360
362
|
@filename = @instance[@attr]
|
361
363
|
@filename = nil if @filename.empty?
|
362
364
|
end
|
363
365
|
|
366
|
+
def store
|
367
|
+
FileColumn.store(store_dir, {:root_path => options[:root_path] }) #root_path is only need for file system store, but pass it in will not hurt for other store
|
368
|
+
end
|
369
|
+
|
364
370
|
def absolute_path(subdir=nil)
|
365
371
|
if subdir
|
366
|
-
|
372
|
+
store.absolute_path(File.join(relative_path_prefix, subdir, @filename))
|
367
373
|
else
|
368
|
-
|
374
|
+
store.absolute_path(File.join(relative_path_prefix, @filename))
|
369
375
|
end
|
370
376
|
end
|
371
377
|
|
372
378
|
def move_from(local_dir, just_uploaded)
|
373
|
-
|
374
|
-
|
379
|
+
store.upload_dir(relative_path_prefix, local_dir)
|
375
380
|
@just_uploaded = just_uploaded
|
376
381
|
end
|
377
382
|
|
@@ -390,7 +395,6 @@ module FileColumn # :nodoc:
|
|
390
395
|
|
391
396
|
def assign_temp(temp_path)
|
392
397
|
return nil if temp_path.nil? or temp_path.empty?
|
393
|
-
|
394
398
|
temp = clone_as TempUploadedFile
|
395
399
|
temp.parse_temp_path(temp_path)
|
396
400
|
temp
|
@@ -401,7 +405,7 @@ module FileColumn # :nodoc:
|
|
401
405
|
end
|
402
406
|
|
403
407
|
def delete_files
|
404
|
-
|
408
|
+
store.delete(relative_path_prefix)
|
405
409
|
end
|
406
410
|
|
407
411
|
private
|
@@ -541,7 +545,7 @@ module FileColumn # :nodoc:
|
|
541
545
|
#
|
542
546
|
# For setting a static storage_dir that doesn't change with respect to a particular
|
543
547
|
# instance, you assign <tt>:storage_dir</tt> a String representing a directory
|
544
|
-
# as
|
548
|
+
# as a relative path under root_path.
|
545
549
|
#
|
546
550
|
# If you need more fine-grained control over the storage directory, you
|
547
551
|
# can use the name of a callback-method as a symbol for the
|
@@ -642,13 +646,13 @@ module FileColumn # :nodoc:
|
|
642
646
|
result
|
643
647
|
end
|
644
648
|
|
649
|
+
private state_method
|
650
|
+
|
645
651
|
define_method "file_column_relative_path_prefix" do
|
646
652
|
raise RuntimeError.new("Trying to access file_column, but primary key got lost.") if self.id.to_s.empty?
|
647
|
-
File.join(*("%08d" % self.id).scan(/..../))
|
653
|
+
options[:use_safe_path] ? File.join(*("%08d" % self.id).scan(/..../)) : self.id.to_s
|
648
654
|
end
|
649
655
|
|
650
|
-
private state_method
|
651
|
-
|
652
656
|
define_method attr do |*args|
|
653
657
|
send(state_method).absolute_path *args
|
654
658
|
end
|
@@ -702,6 +706,7 @@ module FileColumn # :nodoc:
|
|
702
706
|
send(state_method).just_uploaded?
|
703
707
|
end
|
704
708
|
|
709
|
+
|
705
710
|
# this creates a closure keeping a reference to my_options
|
706
711
|
# right now that's the only way we store the options. We
|
707
712
|
# might use a class attribute as well
|
@@ -709,6 +714,30 @@ module FileColumn # :nodoc:
|
|
709
714
|
my_options
|
710
715
|
end
|
711
716
|
|
717
|
+
define_method "#{attr}_download_url" do |context_path, *args|
|
718
|
+
state = send(state_method)
|
719
|
+
relative_path = state.relative_path(*args)
|
720
|
+
return nil unless relative_path
|
721
|
+
|
722
|
+
store = state.store
|
723
|
+
return store.url_for(relative_path) if store && store.respond_to?(:url_for)
|
724
|
+
|
725
|
+
url = ""
|
726
|
+
url << context_path if context_path
|
727
|
+
url << "/"
|
728
|
+
url << state.options[:base_url] << "/"
|
729
|
+
url << relative_path
|
730
|
+
end
|
731
|
+
|
732
|
+
define_method "#{attr}_copy_to" do |local_path, *args|
|
733
|
+
state = send(state_method)
|
734
|
+
relative_path = state.relative_path(*args)
|
735
|
+
return nil unless relative_path
|
736
|
+
store = state.store
|
737
|
+
FileUtils.mkdir_p(File.dirname(local_path))
|
738
|
+
store.copy(relative_path, local_path)
|
739
|
+
end
|
740
|
+
|
712
741
|
private after_save_method, after_destroy_method
|
713
742
|
|
714
743
|
FileColumn::MagickExtension::file_column(self, attr, my_options) if options[:magick]
|
@@ -725,7 +754,8 @@ module FileColumn # :nodoc:
|
|
725
754
|
|
726
755
|
def self.sanitize_filename(filename)
|
727
756
|
filename = File.basename(filename.gsub("\\", "/")) # work-around for IE
|
728
|
-
|
757
|
+
# cannot use \w or \W since Rails enables unicode $KCODE flag
|
758
|
+
filename.gsub!(/[^A-Za-z0-9_\-\.]/, "_")
|
729
759
|
filename = "_#{filename}" if filename =~ /^\.+$/
|
730
760
|
filename = "unnamed" if filename.size == 0
|
731
761
|
filename
|
data/lib/file_column_helper.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# automatically included into ActionView::Base, thereby making this module's
|
4
4
|
# methods available in all your views.
|
5
5
|
module FileColumnHelper
|
6
|
-
|
6
|
+
|
7
7
|
# Use this helper to create an upload field for a file_column attribute. This will generate
|
8
8
|
# an additional hidden field to keep uploaded files during form-redisplays. For example,
|
9
9
|
# when called with
|
@@ -26,7 +26,7 @@ module FileColumnHelper
|
|
26
26
|
result = ActionView::Helpers::InstanceTag.new(object.dup, method.to_s+"_temp", self).to_input_field_tag("hidden", {})
|
27
27
|
result << ActionView::Helpers::InstanceTag.new(object.dup, method, self).to_input_field_tag("file", options)
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Creates an URL where an uploaded file can be accessed. When called for an Entry object with
|
31
31
|
# id 42 (stored in <tt>@entry</tt>) like this
|
32
32
|
#
|
@@ -71,15 +71,10 @@ module FileColumnHelper
|
|
71
71
|
subdir = options
|
72
72
|
end
|
73
73
|
end
|
74
|
-
|
75
|
-
relative_path = object.send("#{method}_relative_path", subdir)
|
76
|
-
return nil unless relative_path
|
77
74
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
url << object.send("#{method}_options")[:base_url] << "/"
|
82
|
-
url << relative_path
|
75
|
+
context_path = absolute ? ActionController::Base.relative_url_root.to_s : nil
|
76
|
+
object.send("#{method}_download_url", context_path, subdir)
|
77
|
+
|
83
78
|
end
|
84
79
|
|
85
80
|
# Same as +url_for_file_colum+ but allows you to access different versions
|
@@ -115,7 +110,7 @@ module FileColumnHelper
|
|
115
110
|
#
|
116
111
|
# and
|
117
112
|
#
|
118
|
-
# <%= url_for_image_column @entry, "image",
|
113
|
+
# <%= url_for_image_column @entry, "image",
|
119
114
|
# :size => "50x50", :crop => "1:1", :name => "thumb" %>
|
120
115
|
#
|
121
116
|
# will produce something like this:
|
data/lib/magick_file_column.rb
CHANGED
@@ -17,7 +17,7 @@ module FileColumn # :nodoc:
|
|
17
17
|
options[:magick][:versions].each_pair do |version, version_options|
|
18
18
|
next if version_options[:lazy]
|
19
19
|
dirname = version_options[:name]
|
20
|
-
FileUtils.
|
20
|
+
FileUtils.mkdir_p File.join(@dir, dirname)
|
21
21
|
transform_image(img, version_options, absolute_path(dirname))
|
22
22
|
end
|
23
23
|
end
|
@@ -55,7 +55,7 @@ module FileColumn # :nodoc:
|
|
55
55
|
return nil
|
56
56
|
end
|
57
57
|
dirname = version_options[:name]
|
58
|
-
FileUtils.
|
58
|
+
FileUtils.mkdir_p File.join(@dir, dirname)
|
59
59
|
transform_image(img, version_options, absolute_path(dirname))
|
60
60
|
end
|
61
61
|
|
data/s3_env.example
CHANGED
data/test/abstract_unit.rb
CHANGED
@@ -64,3 +64,39 @@ class Test::Unit::TestCase
|
|
64
64
|
|
65
65
|
alias_method :f, :file_path
|
66
66
|
end
|
67
|
+
|
68
|
+
# provid a dummy storage implementation for tests
|
69
|
+
|
70
|
+
class InMemoryWithUrlStorageStore
|
71
|
+
def initialize(path_prefix, options)
|
72
|
+
@path_prefix = path_prefix
|
73
|
+
@storage = {}
|
74
|
+
end
|
75
|
+
def upload(path, file)
|
76
|
+
@storage[absolute_path(path) + "/" + File.basename(file)] = File.read(file)
|
77
|
+
end
|
78
|
+
|
79
|
+
def upload_dir(path, local_dir)
|
80
|
+
Dir[File.join(local_dir, "*")].each do |f|
|
81
|
+
upload(path, f)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def exists?(path)
|
86
|
+
File.key?(path)
|
87
|
+
end
|
88
|
+
|
89
|
+
def url_for(path)
|
90
|
+
"store generated url for #{path}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def absolute_path(path)
|
94
|
+
File.join(@path_prefix, path)
|
95
|
+
end
|
96
|
+
|
97
|
+
def clear
|
98
|
+
@storage = {}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
Storage.add_store_class(:in_memory_with_url, InMemoryWithUrlStorageStore)
|
@@ -6,9 +6,19 @@ class UrlForFileColumnTest < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
def setup
|
8
8
|
Entry.file_column :image
|
9
|
+
ActionController::Base.relative_url_root = nil
|
9
10
|
@request = RequestMock.new
|
10
11
|
end
|
11
12
|
|
13
|
+
def test_should_use_store_generated_url_if_file_store_configured_can_do_it
|
14
|
+
FileColumn.config_store(:in_memory_with_url)
|
15
|
+
@e = Entry.new(:image => upload(f("skanthak.png")))
|
16
|
+
assert @e.save
|
17
|
+
assert_equal "store generated url for #{@e.image_relative_path}", url_for_file_column("e", "image")
|
18
|
+
ensure
|
19
|
+
FileColumn.config_store(:filesystem)
|
20
|
+
end
|
21
|
+
|
12
22
|
def test_url_for_file_column_with_temp_entry
|
13
23
|
@e = Entry.new(:image => upload(f("skanthak.png")))
|
14
24
|
url = url_for_file_column("e", "image")
|
@@ -26,7 +36,6 @@ class UrlForFileColumnTest < Test::Unit::TestCase
|
|
26
36
|
def test_url_for_file_column_works_with_symbol
|
27
37
|
@e = Entry.new(:image => upload(f("skanthak.png")))
|
28
38
|
assert @e.save
|
29
|
-
|
30
39
|
url = url_for_file_column(:e, :image)
|
31
40
|
assert_equal "/entry/image/#{@e.file_column_relative_path_prefix}/skanthak.png", url
|
32
41
|
end
|
@@ -52,7 +61,7 @@ class UrlForFileColumnTest < Test::Unit::TestCase
|
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
|
-
class
|
64
|
+
class UrlForFileColumnWithContextPathTest < Test::Unit::TestCase
|
56
65
|
include FileColumnHelper
|
57
66
|
include ActionView::Helpers::AssetTagHelper
|
58
67
|
include ActionView::Helpers::TagHelper
|
@@ -75,7 +84,8 @@ class UrlForFileColumnTest < Test::Unit::TestCase
|
|
75
84
|
def test_with_image_tag
|
76
85
|
e = Entry.new(:image => upload(f("skanthak.png")))
|
77
86
|
html = image_tag url_for_file_column(e, "image")
|
78
|
-
|
87
|
+
|
88
|
+
url = html.scan(/src=\"([^?]+)\?*.*\"/).first.first
|
79
89
|
|
80
90
|
assert_match IMAGE_URL, url
|
81
91
|
end
|
data/test/file_column_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require File.dirname(__FILE__) + '/abstract_unit'
|
2
3
|
|
3
4
|
require File.dirname(__FILE__) + '/fixtures/entry'
|
@@ -39,12 +40,14 @@ class FileColumnTest < Test::Unit::TestCase
|
|
39
40
|
assert_equal "__foo", FileColumn::sanitize_filename('`*foo')
|
40
41
|
assert_equal "foo.txt", FileColumn::sanitize_filename('c:\temp\foo.txt')
|
41
42
|
assert_equal "_.", FileColumn::sanitize_filename(".")
|
43
|
+
assert_equal "a_b.jpg", FileColumn::sanitize_filename("a+b.jpg")
|
42
44
|
end
|
43
45
|
|
46
|
+
|
44
47
|
def test_default_options
|
45
48
|
e = Entry.new
|
46
|
-
assert_match %r{
|
47
|
-
assert_match %r{
|
49
|
+
assert_match %r{entry/image}, e.image_options[:store_dir]
|
50
|
+
assert_match %r{entry/image/tmp}, e.image_options[:tmp_base_dir]
|
48
51
|
end
|
49
52
|
|
50
53
|
def test_assign_without_save_with_tempfile
|
@@ -582,6 +585,13 @@ class FileColumnTest < Test::Unit::TestCase
|
|
582
585
|
e["id"] = nil
|
583
586
|
assert_raise(RuntimeError) { e.image }
|
584
587
|
end
|
588
|
+
|
589
|
+
def test_copy_file_to_local_dir
|
590
|
+
e = Entry.new(:image => upload(f("skanthak.png")))
|
591
|
+
assert e.save
|
592
|
+
e.image_copy_to('/tmp/file_column_test/copy_dir/skanthak.png')
|
593
|
+
assert File.exist?('/tmp/file_column_test/copy_dir/skanthak.png')
|
594
|
+
end
|
585
595
|
end
|
586
596
|
|
587
597
|
# Tests for moving temp dir to permanent dir
|
@@ -650,3 +660,43 @@ class FileColumnMoveTest < Test::Unit::TestCase
|
|
650
660
|
end
|
651
661
|
|
652
662
|
end
|
663
|
+
|
664
|
+
|
665
|
+
# Tests for moving temp dir to permanent dir
|
666
|
+
class FileColumnDownloadUrlTest < Test::Unit::TestCase
|
667
|
+
|
668
|
+
|
669
|
+
def test_default_download_url_is_relative
|
670
|
+
Entry.file_column :image
|
671
|
+
e = Entry.new(:image => upload(f("skanthak.png")))
|
672
|
+
assert e.save
|
673
|
+
|
674
|
+
assert_equal "/entry/image/#{e.id}/skanthak.png", e.image_download_url(nil)
|
675
|
+
end
|
676
|
+
|
677
|
+
def test_download_url_with_specified_url_base
|
678
|
+
Entry.file_column :image, :base_url => 'foo'
|
679
|
+
e = Entry.new(:image => upload(f("skanthak.png")))
|
680
|
+
assert e.save
|
681
|
+
|
682
|
+
assert_equal "/foo/#{e.id}/skanthak.png", e.image_download_url(nil)
|
683
|
+
end
|
684
|
+
|
685
|
+
def test_download_url_with_specified_subdir
|
686
|
+
Entry.file_column :image
|
687
|
+
e = Entry.new(:image => upload(f("skanthak.png")))
|
688
|
+
assert e.save
|
689
|
+
|
690
|
+
assert_equal "/entry/image/#{e.id}/foo/skanthak.png", e.image_download_url(nil, 'foo')
|
691
|
+
end
|
692
|
+
|
693
|
+
|
694
|
+
def test_should_use_store_generated_url_if_storage_configured_can_do_it
|
695
|
+
FileColumn.config_store(:in_memory_with_url)
|
696
|
+
e = Entry.new(:image => upload(f("skanthak.png")))
|
697
|
+
assert e.save
|
698
|
+
assert_equal "store generated url for #{e.image_relative_path}", e.image_download_url(nil)
|
699
|
+
ensure
|
700
|
+
FileColumn.config_store(:filesystem)
|
701
|
+
end
|
702
|
+
end
|
data/test/magick_test.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: file_column_with_s3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Mingle SaaS team
|
@@ -15,13 +15,31 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2013-08-19 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
|
21
|
+
name: mingle-storage
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 29
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
- 0
|
32
|
+
- 1
|
33
|
+
version: 0.0.1
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rails
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
22
40
|
none: false
|
23
41
|
requirements:
|
24
|
-
- -
|
42
|
+
- - ~>
|
25
43
|
- !ruby/object:Gem::Version
|
26
44
|
hash: 19
|
27
45
|
segments:
|
@@ -29,12 +47,12 @@ dependencies:
|
|
29
47
|
- 3
|
30
48
|
- 8
|
31
49
|
version: 2.3.8
|
32
|
-
prerelease: false
|
33
50
|
type: :runtime
|
34
|
-
|
35
|
-
requirement: *id001
|
51
|
+
version_requirements: *id002
|
36
52
|
- !ruby/object:Gem::Dependency
|
37
|
-
|
53
|
+
name: sqlite3
|
54
|
+
prerelease: false
|
55
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
56
|
none: false
|
39
57
|
requirements:
|
40
58
|
- - ">="
|
@@ -43,12 +61,12 @@ dependencies:
|
|
43
61
|
segments:
|
44
62
|
- 0
|
45
63
|
version: "0"
|
46
|
-
prerelease: false
|
47
64
|
type: :development
|
48
|
-
|
49
|
-
requirement: *id002
|
65
|
+
version_requirements: *id003
|
50
66
|
- !ruby/object:Gem::Dependency
|
51
|
-
|
67
|
+
name: rmagick
|
68
|
+
prerelease: false
|
69
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
70
|
none: false
|
53
71
|
requirements:
|
54
72
|
- - ">="
|
@@ -57,10 +75,22 @@ dependencies:
|
|
57
75
|
segments:
|
58
76
|
- 0
|
59
77
|
version: "0"
|
78
|
+
type: :development
|
79
|
+
version_requirements: *id004
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: aws-sdk
|
60
82
|
prerelease: false
|
83
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
hash: 3
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
61
92
|
type: :development
|
62
|
-
|
63
|
-
requirement: *id003
|
93
|
+
version_requirements: *id005
|
64
94
|
description:
|
65
95
|
email: mingle.saas@thoughtworks.com
|
66
96
|
executables: []
|
@@ -71,7 +101,6 @@ extra_rdoc_files: []
|
|
71
101
|
|
72
102
|
files:
|
73
103
|
- Rakefile
|
74
|
-
- lib/file_column/attachement_store.rb
|
75
104
|
- lib/file_column.rb
|
76
105
|
- lib/file_column_helper.rb
|
77
106
|
- lib/file_compat.rb
|
@@ -80,7 +109,6 @@ files:
|
|
80
109
|
- lib/test_case.rb
|
81
110
|
- lib/validations.rb
|
82
111
|
- test/abstract_unit.rb
|
83
|
-
- test/attachement_store_test.rb
|
84
112
|
- test/connection.rb
|
85
113
|
- test/file_column_helper_test.rb
|
86
114
|
- test/file_column_test.rb
|
@@ -124,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
152
|
requirements: []
|
125
153
|
|
126
154
|
rubyforge_project:
|
127
|
-
rubygems_version: 1.8.
|
155
|
+
rubygems_version: 1.8.25
|
128
156
|
signing_key:
|
129
157
|
specification_version: 3
|
130
158
|
summary: File attachment library for ruby
|
@@ -1,93 +0,0 @@
|
|
1
|
-
module FileColumn
|
2
|
-
module AttachementStore
|
3
|
-
begin
|
4
|
-
require 'aws-sdk'
|
5
|
-
class S3Store
|
6
|
-
def initialize(options)
|
7
|
-
s3 = AWS::S3.new(:access_key_id => options[:access_key_id],
|
8
|
-
:secret_access_key => options[:secret_access_key])
|
9
|
-
@bucket = s3.buckets[options[:bucket_name]]
|
10
|
-
end
|
11
|
-
|
12
|
-
def upload(path, local_file)
|
13
|
-
@bucket.objects.create('/' + path + "/" + File.basename(local_file), File.read(local_file))
|
14
|
-
end
|
15
|
-
|
16
|
-
def upload_dir(path, local_dir)
|
17
|
-
@bucket.objects.with_prefix("/" + path).delete_all
|
18
|
-
Dir[File.join(local_dir, "*")].each do |f|
|
19
|
-
upload(path, f)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def read(path)
|
24
|
-
@bucket.objects["/" + path ].read
|
25
|
-
end
|
26
|
-
|
27
|
-
def exists?(path)
|
28
|
-
@bucket.objects['/' + path].exists?
|
29
|
-
end
|
30
|
-
|
31
|
-
def clear
|
32
|
-
@bucket.clear!
|
33
|
-
end
|
34
|
-
end
|
35
|
-
rescue LoadError => e
|
36
|
-
puts "Warning: can not load aws-sdk gem, s3 file store disabled"
|
37
|
-
end
|
38
|
-
|
39
|
-
class FilesystemStore
|
40
|
-
def initialize(dir)
|
41
|
-
@dir = dir
|
42
|
-
FileUtils.mkdir_p @dir
|
43
|
-
end
|
44
|
-
|
45
|
-
def read(path)
|
46
|
-
File.read(absolute_path(path))
|
47
|
-
end
|
48
|
-
|
49
|
-
def upload(path, local_file)
|
50
|
-
FileUtils.mkdir_p(absolute_path(path))
|
51
|
-
FileUtils.mv(local_file, absolute_path(path))
|
52
|
-
end
|
53
|
-
|
54
|
-
def upload_dir(path, local_dir)
|
55
|
-
FileUtils.rm_rf(absolute_path(path))
|
56
|
-
Dir[File.join(local_dir, "*")].each do |f|
|
57
|
-
upload(path, f)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
#todo: this should be interface that retrive a lazy file object
|
62
|
-
def absolute_path(*relative_paths)
|
63
|
-
File.join(@dir, *relative_paths)
|
64
|
-
end
|
65
|
-
|
66
|
-
def exists?(file_path)
|
67
|
-
File.exists?(absolute_path(file_path))
|
68
|
-
end
|
69
|
-
|
70
|
-
def clear
|
71
|
-
FileUtils.rm_rf @dir
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class Builder
|
76
|
-
def initialize(*build_opts)
|
77
|
-
@type, *@build_opts = *build_opts
|
78
|
-
end
|
79
|
-
|
80
|
-
def build(dir=nil)
|
81
|
-
args = @build_opts
|
82
|
-
args += [dir] if @type == :filesystem
|
83
|
-
store_class.new(*args)
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def store_class
|
89
|
-
ActiveSupport::Inflector.constantize("FileColumn::AttachementStore::#{ActiveSupport::Inflector.camelize(@type)}Store")
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1,96 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
-
require 'active_support/test_case'
|
3
|
-
|
4
|
-
class AttachementStoreTest < Test::Unit::TestCase
|
5
|
-
extend Test::Unit::Assertions
|
6
|
-
|
7
|
-
STORE_DIR = File.dirname(__FILE__)+"/public/entry"
|
8
|
-
STORE_BUILD_OPTS = [[:filesystem]]
|
9
|
-
if !ENV["S3_ACCESS_KEY_ID"].blank?
|
10
|
-
STORE_BUILD_OPTS << [:s3, {
|
11
|
-
:access_key_id => ENV["S3_ACCESS_KEY_ID"],
|
12
|
-
:secret_access_key => ENV["S3_SECRET_ACCESS_KEY"],
|
13
|
-
:bucket_name => ENV["S3_BUCKET_NAME"]}]
|
14
|
-
end
|
15
|
-
|
16
|
-
def teardown
|
17
|
-
FileColumn.store(STORE_DIR).clear
|
18
|
-
FileUtils.rm_rf("/tmp/file_column_test")
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.store_test(test_name, store_type, *store_building_args, &block)
|
22
|
-
define_method(test_name + "_for_#{store_type}_store") do
|
23
|
-
FileColumn.store = store_type, *store_building_args
|
24
|
-
yield
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
STORE_BUILD_OPTS.each do |store_type, *rest_args|
|
30
|
-
store_test "test_build_right_store", store_type, *rest_args do
|
31
|
-
assert FileColumn.store("/tmp/attachements").class.name.include?(ActiveSupport::Inflector.camelize(store_type))
|
32
|
-
end
|
33
|
-
|
34
|
-
store_test "test_upload_local_file", store_type, *rest_args do
|
35
|
-
file = "/tmp/file_column_test/abc"
|
36
|
-
FileUtils.mkdir_p(File.dirname(file))
|
37
|
-
FileUtils.touch(file)
|
38
|
-
store = FileColumn.store(STORE_DIR)
|
39
|
-
store.upload("x/y/z", file)
|
40
|
-
assert !store.exists?("x/abc")
|
41
|
-
assert store.exists?("x/y/z/abc")
|
42
|
-
assert_equal "", store.read("x/y/z/abc")
|
43
|
-
end
|
44
|
-
|
45
|
-
store_test "test_upload_with_same_name_replace_file", store_type, *rest_args do
|
46
|
-
file = "/tmp/file_column_test/abc"
|
47
|
-
FileUtils.mkdir_p(File.dirname(file))
|
48
|
-
File.open(file, "w+") { |f| f << "123" }
|
49
|
-
|
50
|
-
store = FileColumn.store(STORE_DIR)
|
51
|
-
store.upload("x/y/z", file)
|
52
|
-
|
53
|
-
assert_equal "123", store.read("x/y/z/abc")
|
54
|
-
|
55
|
-
File.open(file, "w+") { |f| f << "456" }
|
56
|
-
store.upload("x/y/z", file)
|
57
|
-
|
58
|
-
assert_equal "456", store.read("x/y/z/abc")
|
59
|
-
end
|
60
|
-
|
61
|
-
store_test "test_upload_local_dir", store_type, *rest_args do
|
62
|
-
local_dir = "/tmp/file_column_test"
|
63
|
-
FileUtils.mkdir_p(local_dir)
|
64
|
-
FileUtils.touch(File.join(local_dir, "a"))
|
65
|
-
FileUtils.touch(File.join(local_dir, "b"))
|
66
|
-
|
67
|
-
store = FileColumn.store(STORE_DIR)
|
68
|
-
store.upload_dir("x/y/z", local_dir)
|
69
|
-
|
70
|
-
assert store.exists?("x/y/z/a")
|
71
|
-
assert store.exists?("x/y/z/b")
|
72
|
-
end
|
73
|
-
|
74
|
-
|
75
|
-
store_test "test_upload_local_dir_with_replace_files", store_type, *rest_args do
|
76
|
-
|
77
|
-
local_dir = "/tmp/file_column_test/old"
|
78
|
-
FileUtils.mkdir_p(local_dir)
|
79
|
-
FileUtils.touch(File.join(local_dir, "a"))
|
80
|
-
|
81
|
-
store = FileColumn.store(STORE_DIR)
|
82
|
-
store.upload_dir("x/y/z", local_dir)
|
83
|
-
|
84
|
-
local_dir = "/tmp/file_column_test/new"
|
85
|
-
FileUtils.mkdir_p(local_dir)
|
86
|
-
FileUtils.touch(File.join(local_dir, "b"))
|
87
|
-
|
88
|
-
store = FileColumn.store(STORE_DIR)
|
89
|
-
store.upload_dir("x/y/z", local_dir)
|
90
|
-
|
91
|
-
assert store.exists?("x/y/z/b")
|
92
|
-
assert !store.exists?("x/y/z/a")
|
93
|
-
end
|
94
|
-
|
95
|
-
end
|
96
|
-
end
|