expiring_asset_links 1.2.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -30,22 +30,10 @@ or add it to your Gemfile
30
30
 
31
31
  your configuration must satisfy the following requirements:
32
32
 
33
- * specify `storage :fog`
34
- * use the default `store_dir` string or one that ends with `folder/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}`
33
+ * define `storage :fog`
34
+ * set `Expires` in `s3_headers`
35
35
 
36
- any of the following will work
37
-
38
- <pre>
39
- uploads/#{Rails.env}/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}
40
- uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}
41
- #{Rails.env}/uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}
42
- #{Rails.env}/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}
43
- a/series/of/folder/names/or/1/numbers/2/that_do/not/contain/spaces/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}
44
- </pre>
45
-
46
- * `s3_headers` must include a value for `Expires`
47
-
48
- for example
36
+ >
49
37
 
50
38
  class AssetUploader < CarrierWave::Uploader::Base
51
39
  storage :fog
@@ -60,6 +48,21 @@ for example
60
48
 
61
49
  end
62
50
 
51
+ ### add an initializer with your CarrierWave Uploader `store_dir` matching Regexp
52
+
53
+ if you wish to change the default `store_dir` in your CarrierWave Uploader you will need to create a Regexp that captures the object class name and id from the path
54
+
55
+ create an initializer, such as `config/initializers/expiring_asset_links.rb` and include your configuration with Regexp
56
+
57
+ ExpiringAssetLinks.configure do |conf|
58
+ conf.fog_directory = /\/\S+\/(?<name>[a-z_]+)\/[a-z_]+\/(?<id>\d+)/
59
+ end
60
+
61
+ the path defined in CarrierWave Uploader `store_dir`, such as `uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}`, must match the Regexp in your configuration once generated by CarrierWave and must capture the class name as `<name>` and the object id as `<id>`
62
+
63
+ /\/\S+\/(?<name>[a-z_]+)\/[a-z_]+\/(?<id>\d+)/.match("uploads/class_name/uploader_name/100")
64
+ #=> #<MatchData "uploads/class_name/uploader_name/100" name:"model_class_name" id:"100">
65
+
63
66
  ### mount an uploader for any class containing an assets
64
67
 
65
68
  you may use as many different classes as you would like, but each may only contain one mounted uploader
@@ -87,3 +90,28 @@ the attributes specified should contain fully qualified asset URLs generated by
87
90
  attr_expiring_asset_links :summary, :body
88
91
 
89
92
  end
93
+
94
+ ## Notes
95
+
96
+ the url that is generated by CarrierWave may not immediately follow a letter or underscore in the content of the attribute specified as `attr_expiring_asset_links`, this will prevent the gem from properly parsing the data
97
+
98
+ example of proper placement (the double quote character is no a letter or an underscore)
99
+
100
+ <h2>
101
+ Section One
102
+ </h2>
103
+ <p>
104
+ This is the first section in the body of the document.
105
+ It includes an image.
106
+ </p>
107
+ <img src="https://test.s3-us-east-1.amazonaws.com/uploads/test/99/asset/file_attachment/sample.jpg">
108
+
109
+ example of improper placement (no space between 'at' and 'https')
110
+
111
+ <h2>
112
+ Section One
113
+ </h2>
114
+ <p>
115
+ This is the first section in the body of the document.
116
+ It includes an image, you may view it athttps://test.s3-us-east-1.amazonaws.com/uploads/test/99/asset/file_attachment/sample.jpg
117
+ </p>
@@ -1,12 +1,22 @@
1
1
  require 'active_record'
2
+ require 'expiring_asset_links/configuration'
2
3
 
3
4
  module ExpiringAssetLinks
4
5
  autoload :Version, 'expiring_asset_links/version'
5
-
6
- def self.extended(base)
7
- base.class_eval do
8
- @expiring_asset_link_attributes = []
9
- include InstanceMethods
6
+ extend ExpiringAssetLinks::Configuration
7
+
8
+ class << self
9
+
10
+ def extended(base)
11
+ base.class_eval do
12
+ @expiring_asset_link_attributes = []
13
+ include InstanceMethods
14
+ end
15
+ end
16
+
17
+ def remove_asset_tags(value)
18
+ asset_url = Regexp::new "https://" + [/#{CarrierWave::Uploader::Base.fog_directory}\.s3\S+[amazon|amazonaws]\.com\//, self.fog_directory, /\/\S+Expires=[\d]{10}/].flatten.map{ |re| re.source }.join.gsub('\\/\\/', '\\/')
19
+ value.gsub(asset_url, '\k<name>{{\k<id>}}').gsub(/([A-Za-z_]+)\{\{(\d+)\}\}/) { "#{$1.classify}{{#{$2}}}" }
10
20
  end
11
21
  end
12
22
 
@@ -33,12 +43,11 @@ module ExpiringAssetLinks
33
43
  protected
34
44
 
35
45
  def remove_asset_tags(attribute)
36
- self[attribute.to_sym].gsub(/https:\/\/#{CarrierWave::Uploader::Base.fog_directory}\.s3.\S+\/([a-z_]+)\/[a-z_]+\/(\d+)\/\S+Expires=[\d]{10}/) { "#{$1.classify}{{#{$2}}}" }
46
+ ExpiringAssetLinks.remove_asset_tags(self[attribute.to_sym])
37
47
  end
38
48
 
39
49
  def add_asset_tags(attribute)
40
- linked_attribute =
41
- self[attribute.to_sym].gsub(/([A-Za-z]+)\{\{(\d+)\}\}/) { $1.constantize.find($2).send($1.constantize.uploaders.keys.first).url(:default) }
50
+ linked_attribute = self[attribute.to_sym].gsub(/([A-Za-z]+)\{\{(\d+)\}\}/) { $1.constantize.find($2).send($1.constantize.uploaders.keys.first).url(:default) }
42
51
  end
43
52
 
44
53
  def remove_all_asset_tags!
@@ -0,0 +1,22 @@
1
+ module ExpiringAssetLinks
2
+ module Configuration
3
+ VALID_CONFIG_KEYS = [:fog_directory].freeze
4
+ DEFAULT_FOG_DIRECTORY ||= /\S+\/(?<name>[a-z_]+)\/[a-z_]+\/(?<id>\d+)/
5
+ attr_accessor *VALID_CONFIG_KEYS
6
+
7
+ def self.extended(base)
8
+ base.reset
9
+ end
10
+
11
+ def reset
12
+ self.fog_directory = DEFAULT_FOG_DIRECTORY
13
+ end
14
+
15
+ def configure
16
+ yield self
17
+ raise TypeError, "expected fog_directory to be a Regexp" unless self.fog_directory.is_a?(Regexp)
18
+ missing_names = ["name", "id"] - self.fog_directory.names
19
+ raise RegexpError, "fog_directory must capture #{missing_names.join(' and ')}" unless missing_names.empty?
20
+ end
21
+ end
22
+ end
@@ -2,8 +2,8 @@ module ExpiringAssetLinks
2
2
  # Contains information about this gem's version
3
3
  module Version
4
4
  MAJOR = 1
5
- MINOR = 2
6
- PATCH = 0
5
+ MINOR = 3
6
+ PATCH = 1
7
7
 
8
8
  # Returns a version string by joining <tt>MAJOR</tt>, <tt>MINOR</tt>, and <tt>PATCH</tt> with <tt>'.'</tt>
9
9
  #
@@ -1,11 +1,10 @@
1
1
  require File.expand_path('../test_helper', __FILE__)
2
2
 
3
3
  class ExpiringAssetLinksTest < Test::Unit::TestCase
4
-
5
4
  def setup
6
5
  CarrierWave.configure do |config|
7
6
  # config.cache_dir = "#{Rails.root}/tmp/assets"
8
- #
7
+ #
9
8
  # config.root = Rails.root.join('tmp')
10
9
  # config.cache_dir = "assets"
11
10
  # config.fog_credentials = {
@@ -19,12 +18,118 @@ class ExpiringAssetLinksTest < Test::Unit::TestCase
19
18
  end
20
19
  end
21
20
 
22
- def test_should_assert_true
23
- file_attachment = FileAttachment.create(name: "test", asset: AssetUploader.new("https://test.s3-us-east-1.amazonaws.com/uploads/test/file_attachment/asset/1/sample.jpg"))
21
+ def test_class_id_path
22
+ ExpiringAssetLinks.configure do |conf|
23
+ conf.fog_directory = /\S+\/(?<name>[a-z_]+)\/[a-z_]+\/(?<id>\d+)/
24
+ end
25
+
26
+ file_attachment = FileAttachment.create(name: "test")
27
+ file_path = "https://test.s3-us-east-1.amazonaws.com/uploads/test/file_attachment/asset/#{file_attachment.id}/sample.jpg"
28
+ file_attachment.update_attributes({asset: AssetUploader.new(file_path)})
29
+ document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">")
30
+
31
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{#{file_attachment.id}}}\">", Document.find(document.id).attributes["body"]
32
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_path}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
33
+ end
34
+
35
+ def test_id_class_path
36
+ ExpiringAssetLinks.configure do |conf|
37
+ conf.fog_directory = /\S+\/(?<id>\d+)\/[a-z_]+\/(?<name>[a-z_]+)/
38
+ end
39
+
40
+ file_attachment = FileAttachment.create(name: "test")
41
+ file_path = "https://test.s3-us-east-1.amazonaws.com/uploads/test/#{file_attachment.id}/asset/file_attachment/sample.jpg"
42
+ file_attachment.update_attributes({asset: AssetUploader.new(file_path)})
43
+ document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">")
44
+
45
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{#{file_attachment.id}}}\">", Document.find(document.id).attributes["body"]
46
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_path}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
47
+ end
48
+
49
+ def test_default_configuration
50
+ file_attachment = FileAttachment.create(name: "test")
51
+ file_path = "https://test.s3-us-east-1.amazonaws.com/uploads/test/file_attachment/asset/#{file_attachment.id}/sample.jpg"
52
+ file_attachment.update_attributes({asset: AssetUploader.new(file_path)})
53
+ document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">")
54
+
55
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{#{file_attachment.id}}}\">", Document.find(document.id).attributes["body"]
56
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_path}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
57
+ end
58
+
59
+ def test_wrong_type_fog_directory_configuration
60
+ assert_raises(TypeError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = "" } }
61
+ assert_raises(TypeError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = "test" } }
62
+ assert_raises(TypeError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = "\S+\/(?<id>\d+)\/[a-z_]+\/(?<name>[a-z_]+)" } }
63
+ end
64
+
65
+ def test_invalid_fog_directory_configuration
66
+ assert_raises(RegexpError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = // } }
67
+ assert_raises(RegexpError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = /\S+\/(\d+)\/[a-z_]+\/([a-z_]+)/ } }
68
+ assert_raises(RegexpError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = /\S+\/(\d+)\/[a-z_]+\/(?<name>[a-z_]+)/ } }
69
+ assert_raises(RegexpError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = /\S+\/(?<id>\d+)\/[a-z_]+\/([a-z_]+)/ } }
70
+ assert_raises(RegexpError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = /\S+\/(?<ids>\d+)\/[a-z_]+\/(?<name>[a-z_]+)/ } }
71
+ assert_raises(RegexpError) { ExpiringAssetLinks.configure { |conf| conf.fog_directory = /\S+\/(?<id>\d+)\/[a-z_]+\/(?<names>[a-z_]+)/ } }
72
+ end
73
+
74
+ def test_extra_names_fog_directory_configuration
75
+ ExpiringAssetLinks.configure do |conf|
76
+ conf.fog_directory = /\S+\/(?<id>\d+)\/(?<mount>[a-z_]+)\/(?<name>[a-z_]+)/
77
+ end
78
+
79
+ file_attachment = FileAttachment.create(name: "test")
80
+ file_path = "https://test.s3-us-east-1.amazonaws.com/uploads/test/#{file_attachment.id}/asset/file_attachment/sample.jpg"
81
+ file_attachment.update_attributes({asset: AssetUploader.new(file_path)})
82
+ document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">")
83
+
84
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{#{file_attachment.id}}}\">", Document.find(document.id).attributes["body"]
85
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_path}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
86
+ end
87
+
88
+ def test_non_matching_fog_directory_configuration
89
+ # there is essentially no way of knowing that a non-matching URL string should have matched the Regexp,
90
+ # no validation of any type is performed when adding or removing asset links
91
+ ExpiringAssetLinks.configure do |conf|
92
+ conf.fog_directory = /\S+\/(?<id>\d+)\/[a-z_]+\/(?<name>[a-z_]+)\/error/
93
+ end
94
+
95
+ file_attachment = FileAttachment.create(name: "test")
96
+ file_path = "https://test.s3-us-east-1.amazonaws.com/uploads/test/#{file_attachment.id}/asset/file_attachment/sample.jpg"
97
+ file_attachment.update_attributes({asset: AssetUploader.new(file_path)})
98
+ document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">")
99
+
100
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">", Document.find(document.id).attributes["body"]
101
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">", Document.find(document.id).body
102
+ end
103
+
104
+ def test_multiple_assets
105
+ ExpiringAssetLinks.configure do |conf|
106
+ conf.fog_directory = /\S+\/(?<id>\d+)\/[a-z_]+\/(?<name>[a-z_]+)/
107
+ end
108
+
109
+ file_attachment_a = FileAttachment.create(name: "test")
110
+ file_path_a = "https://test.s3-us-east-1.amazonaws.com/uploads/test/#{file_attachment_a.id}/asset/file_attachment/sample.jpg"
111
+ file_attachment_a.update_attributes({asset: AssetUploader.new(file_path_a)})
112
+ file_attachment_b = FileAttachment.create(name: "test")
113
+ file_path_b = "https://test.s3-us-east-1.amazonaws.com/uploads/test/#{file_attachment_b.id}/asset/file_attachment/sample.jpg"
114
+ file_attachment_b.update_attributes({asset: AssetUploader.new(file_path_b)})
115
+ document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment_a.send(FileAttachment.uploaders.keys.first).url}\"><p>And another image.</p><img src=\"#{file_attachment_b.send(FileAttachment.uploaders.keys.first).url}\">")
116
+
117
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{#{file_attachment_a.id}}}\"><p>And another image.</p><img src=\"FileAttachment{{#{file_attachment_b.id}}}\">", Document.find(document.id).attributes["body"]
118
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_path_a}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\"><p>And another image.</p><img src=\"#{file_path_b}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
119
+ end
120
+
121
+ def test_with_leading_forward_slash_path
122
+ ExpiringAssetLinks.configure do |conf|
123
+ conf.fog_directory = /\/\S+\/(?<name>[a-z_]+)\/[a-z_]+\/(?<id>\d+)/
124
+ end
125
+
126
+ file_attachment = FileAttachment.create(name: "test")
127
+ file_path = "https://test.s3-us-east-1.amazonaws.com/uploads/test/file_attachment/asset/#{file_attachment.id}/sample.jpg"
128
+ file_attachment.update_attributes({asset: AssetUploader.new(file_path)})
24
129
  document = Document.create(title: "This is the Document Title", body: "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_attachment.send(FileAttachment.uploaders.keys.first).url}\">")
25
130
 
26
- assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{1}}\">", Document.find(document.id).attributes["body"]
27
- assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"https://test.s3-us-east-1.amazonaws.com/uploads/test/file_attachment/asset/1/sample.jpg?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
131
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"FileAttachment{{#{file_attachment.id}}}\">", Document.find(document.id).attributes["body"]
132
+ assert_equal "<h2>Section One</h2><p>This is the first section in the body of the document. It includes an image.</p><img src=\"#{file_path}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222\">", Document.find(document.id).body
28
133
  end
29
134
 
30
135
  end
@@ -12,19 +12,16 @@ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":me
12
12
 
13
13
  ActiveRecord::Schema.define(:version => 1) do
14
14
  create_table :documents do |t|
15
- t.integer :id
16
15
  t.string :title
17
16
  t.text :body
18
17
  end
19
18
  create_table :file_attachments do |t|
20
- t.integer :id
21
- t.integer :name
22
- t.binary :asset
19
+ t.string :name
20
+ t.binary :asset
23
21
  end
24
22
  create_table :image_attachments do |t|
25
- t.integer :id
26
- t.integer :name
27
- t.binary :asset
23
+ t.string :name
24
+ t.binary :asset
28
25
  end
29
26
  end
30
27
 
@@ -60,5 +57,3 @@ class AssetUploader < Struct.new(:my_url)
60
57
  "#{self.my_url}?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&amp;Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXX%3D&amp;Expires=2222222222"
61
58
  end
62
59
  end
63
-
64
-
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: expiring_asset_links
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-12 00:00:00.000000000 Z
12
+ date: 2013-10-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: carrierwave
@@ -88,6 +88,7 @@ files:
88
88
  - Rakefile
89
89
  - expiring_asset_links.gemspec
90
90
  - lib/expiring_asset_links.rb
91
+ - lib/expiring_asset_links/configuration.rb
91
92
  - lib/expiring_asset_links/version.rb
92
93
  - test/expiring_asset_links_test.rb
93
94
  - test/test_helper.rb