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 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 'file_column/attachement_store'
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
- #todo: dir is not required for all type of store
22
- def self.store(dir)
23
- (@store_builder || AttachementStore::Builder.new(:filesystem)).build(dir)
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.store=(args)
27
- @store_builder = AttachementStore::Builder.new(*args)
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(options[:root_path], model, attr)
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
- FileUtils.mkdir(@dir)
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
- @store.absolute_path(File.join(relative_path_prefix, subdir, @filename))
372
+ store.absolute_path(File.join(relative_path_prefix, subdir, @filename))
367
373
  else
368
- @store.absolute_path(File.join(relative_path_prefix, @filename))
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
- @store.upload_dir(relative_path_prefix, local_dir)
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
- @store.clear
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 an absolute path.
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
- filename.gsub!(/[^a-zA-Z0-9\.\-\+_]/,"_")
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
@@ -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
- url = ""
79
- url << ActionController::Base.relative_url_root.to_s if absolute
80
- url << "/"
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:
@@ -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.mkdir File.join(@dir, dirname)
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.mkdir File.join(@dir, dirname)
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
@@ -1,5 +1,5 @@
1
1
  #!/bin/sh
2
2
 
3
- export S3_ACCESS_KEY_ID=<key-id>
4
- export S3_SECRET_ACCESS_KEY=<access-key>
3
+ export AWS_ACCESS_KEY_ID=<key-id>
4
+ export AWS_SECRET_ACCESS_KEY=<access-key>
5
5
  export S3_BUCKET_NAME=file-column-attachement-test
@@ -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 UrlForFileColumnTest < Test::Unit::TestCase
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
- url = html.scan(/src=\"(.+)\?.*\"/).first.first
87
+
88
+ url = html.scan(/src=\"([^?]+)\?*.*\"/).first.first
79
89
 
80
90
  assert_match IMAGE_URL, url
81
91
  end
@@ -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{/public/entry/image}, e.image_options[:store_dir]
47
- assert_match %r{/public/entry/image/tmp}, e.image_options[:tmp_base_dir]
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
@@ -1,5 +1,4 @@
1
1
  begin
2
- require 'RMagick'
3
2
  require File.dirname(__FILE__) + '/abstract_unit'
4
3
  require File.dirname(__FILE__) + '/fixtures/entry'
5
4
 
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: 25
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 1
10
- version: 0.1.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: 2012-09-20 00:00:00 Z
18
+ date: 2013-08-19 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- version_requirements: &id001 !ruby/object:Gem::Requirement
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
- name: rails
35
- requirement: *id001
51
+ version_requirements: *id002
36
52
  - !ruby/object:Gem::Dependency
37
- version_requirements: &id002 !ruby/object:Gem::Requirement
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
- name: sqlite3
49
- requirement: *id002
65
+ version_requirements: *id003
50
66
  - !ruby/object:Gem::Dependency
51
- version_requirements: &id003 !ruby/object:Gem::Requirement
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
- name: rmagick
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.24
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