refile-s3 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 99dbc8a79977f2f3ab2ec3d0baf5559378621850
4
+ data.tar.gz: 04db099371048f327bc1bb44c23339a44ecc8bee
5
+ SHA512:
6
+ metadata.gz: 104de7b88e8b1a79f628154452ad25ca4668a6e92090376b7f4a8dde10cf24b6fe9bd64831b2955b34d6a428386618e4b9debbc41c874bc24546727a797a1740
7
+ data.tar.gz: 0dece4b7f10e3d501e70bd18e45285514bbacc5b9966b0db06d8c90a8038d791882ad1deabc89c7fc76cd99abe2f48fc3fd573048d858f8c36e592eb8fd24524
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ s3.yml
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in refile-s3.gemspec
4
+ gemspec
5
+
6
+ gem "refile", github: "refile/refile"
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Jonas Nicklas
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # Refile::S3
2
+
3
+ Amazon S3 backend for the [Refile][gh] gem. See the Refile documentation for
4
+ more details.
5
+
6
+ ## License
7
+
8
+ [MIT](LICENSE.txt)
9
+
10
+ [gh]: http://github.com/refile/refile
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: "spec"
7
+
data/lib/refile/s3.rb ADDED
@@ -0,0 +1,149 @@
1
+ require "aws-sdk"
2
+ require "open-uri"
3
+ require "refile"
4
+ require "refile/s3/version"
5
+
6
+ module Refile
7
+ # A refile backend which stores files in Amazon S3
8
+ #
9
+ # @example
10
+ # backend = Refile::Backend::S3.new(
11
+ # access_key_id: "xyz",
12
+ # secret_access_key: "abcd1234",
13
+ # region: "sa-east-1",
14
+ # bucket: "my-bucket",
15
+ # prefix: "files"
16
+ # )
17
+ # file = backend.upload(StringIO.new("hello"))
18
+ # backend.read(file.id) # => "hello"
19
+ class S3
20
+ extend Refile::BackendMacros
21
+
22
+ attr_reader :access_key_id, :max_size
23
+
24
+ # Sets up an S3 backend with the given credentials.
25
+ #
26
+ # @param [String] access_key_id
27
+ # @param [String] secret_access_key
28
+ # @param [String] region The AWS region to connect to
29
+ # @param [String] bucket The name of the bucket where files will be stored
30
+ # @param [String] prefix A prefix to add to all files. Prefixes on S3 are kind of like folders.
31
+ # @param [Integer, nil] max_size The maximum size of an uploaded file
32
+ # @param [#hash] hasher A hasher which is used to generate ids from files
33
+ # @param [Hash] s3_options Additional options to initialize S3 with
34
+ # @see http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/Core/Configuration.html
35
+ # @see http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3.html
36
+ def initialize(access_key_id:, secret_access_key:, region:, bucket:, max_size: nil, prefix: nil, hasher: Refile::RandomHasher.new, **s3_options)
37
+ @access_key_id = access_key_id
38
+ @secret_access_key = secret_access_key
39
+ @s3_options = { access_key_id: access_key_id, secret_access_key: secret_access_key, region: region }.merge s3_options
40
+ @s3 = Aws::S3::Resource.new @s3_options
41
+ @bucket_name = bucket
42
+ @bucket = @s3.bucket @bucket_name
43
+ @hasher = hasher
44
+ @prefix = prefix
45
+ @max_size = max_size
46
+ end
47
+
48
+ # Upload a file into this backend
49
+ #
50
+ # @param [IO] uploadable An uploadable IO-like object.
51
+ # @return [Refile::File] The uploaded file
52
+ verify_uploadable def upload(uploadable)
53
+ id = @hasher.hash(uploadable)
54
+
55
+ if uploadable.is_a?(Refile::File) and uploadable.backend.is_a?(S3) and uploadable.backend.access_key_id == access_key_id
56
+ object(id).copy_from(copy_source: [@bucket_name, uploadable.backend.object(uploadable.id).key].join("/"))
57
+ else
58
+ object(id).put(body: uploadable, content_length: uploadable.size)
59
+ end
60
+
61
+ Refile::File.new(self, id)
62
+ end
63
+
64
+ # Get a file from this backend.
65
+ #
66
+ # Note that this method will always return a {Refile::File} object, even
67
+ # if a file with the given id does not exist in this backend. Use
68
+ # {FileSystem#exists?} to check if the file actually exists.
69
+ #
70
+ # @param [Sring] id The id of the file
71
+ # @return [Refile::File] The retrieved file
72
+ verify_id def get(id)
73
+ Refile::File.new(self, id)
74
+ end
75
+
76
+ # Delete a file from this backend
77
+ #
78
+ # @param [Sring] id The id of the file
79
+ # @return [void]
80
+ verify_id def delete(id)
81
+ object(id).delete
82
+ end
83
+
84
+ # Return an IO object for the uploaded file which can be used to read its
85
+ # content.
86
+ #
87
+ # @param [Sring] id The id of the file
88
+ # @return [IO] An IO object containing the file contents
89
+ verify_id def open(id)
90
+ Kernel.open(object(id).presigned_url(:get))
91
+ end
92
+
93
+ # Return the entire contents of the uploaded file as a String.
94
+ #
95
+ # @param [String] id The id of the file
96
+ # @return [String] The file's contents
97
+ verify_id def read(id)
98
+ object(id).get.body.read
99
+ rescue Aws::S3::Errors::NoSuchKey
100
+ nil
101
+ end
102
+
103
+ # Return the size in bytes of the uploaded file.
104
+ #
105
+ # @param [Sring] id The id of the file
106
+ # @return [Integer] The file's size
107
+ verify_id def size(id)
108
+ object(id).get.content_length
109
+ rescue Aws::S3::Errors::NoSuchKey
110
+ nil
111
+ end
112
+
113
+ # Return whether the file with the given id exists in this backend.
114
+ #
115
+ # @param [Sring] id The id of the file
116
+ # @return [Boolean]
117
+ verify_id def exists?(id)
118
+ object(id).exists?
119
+ end
120
+
121
+ # Remove all files in this backend. You must confirm the deletion by
122
+ # passing the symbol `:confirm` as an argument to this method.
123
+ #
124
+ # @example
125
+ # backend.clear!(:confirm)
126
+ # @raise [Refile::Confirm] Unless the `:confirm` symbol has been passed.
127
+ # @param [:confirm] confirm Pass the symbol `:confirm` to confirm deletion.
128
+ # @return [void]
129
+ def clear!(confirm = nil)
130
+ raise Refile::Confirm unless confirm == :confirm
131
+ @bucket.objects(prefix: @prefix).delete
132
+ end
133
+
134
+ # Return a presign signature which can be used to upload a file into this
135
+ # backend directly.
136
+ #
137
+ # @return [Refile::Signature]
138
+ def presign
139
+ id = RandomHasher.new.hash
140
+ signature = @bucket.presigned_post(key: [*@prefix, id].join("/"))
141
+ signature.content_length_range(0..@max_size) if @max_size
142
+ Signature.new(as: "file", id: id, url: signature.url.to_s, fields: signature.fields)
143
+ end
144
+
145
+ verify_id def object(id)
146
+ @bucket.object([*@prefix, id].join("/"))
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,5 @@
1
+ module Refile
2
+ class S3
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
data/refile-s3.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'refile/s3/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "refile-s3"
8
+ spec.version = Refile::S3::VERSION
9
+ spec.authors = ["Jonas Nicklas"]
10
+ spec.email = ["jonas.nicklas@gmail.com"]
11
+ spec.summary = "Amazon S3 backend for the Refile gem"
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency "refile", "~> 0.5.0"
21
+ spec.add_dependency "aws-sdk", "~> 2.0"
22
+ spec.add_development_dependency "bundler", "~> 1.7"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency "webmock"
26
+ end
@@ -0,0 +1,12 @@
1
+ require "refile/spec_helper"
2
+ require "refile/s3"
3
+
4
+ WebMock.allow_net_connect!
5
+
6
+ config = YAML.load_file("s3.yml").map { |k, v| [k.to_sym, v] }.to_h
7
+
8
+ RSpec.describe Refile::S3 do
9
+ let(:backend) { Refile::S3.new(max_size: 100, **config) }
10
+
11
+ it_behaves_like :backend
12
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: refile-s3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonas Nicklas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: refile
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.5.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.5.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description:
98
+ email:
99
+ - jonas.nicklas@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - Gemfile
106
+ - LICENSE.txt
107
+ - README.md
108
+ - Rakefile
109
+ - lib/refile/s3.rb
110
+ - lib/refile/s3/version.rb
111
+ - refile-s3.gemspec
112
+ - spec/refile/s3_spec.rb
113
+ homepage: ''
114
+ licenses:
115
+ - MIT
116
+ metadata: {}
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ required_rubygems_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ requirements: []
132
+ rubyforge_project:
133
+ rubygems_version: 2.4.5
134
+ signing_key:
135
+ specification_version: 4
136
+ summary: Amazon S3 backend for the Refile gem
137
+ test_files:
138
+ - spec/refile/s3_spec.rb