file_column_with_s3 0.1.1 → 0.1.2
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/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
|