neofiles 1.1.4 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/concerns/neofiles/data_store/mongo/file_helper.rb +22 -0
- data/app/models/neofiles/data_store.rb +2 -0
- data/app/models/neofiles/data_store/amazon_s3.rb +95 -0
- data/app/models/neofiles/data_store/mongo.rb +132 -0
- data/app/models/neofiles/data_store/not_found_exception.rb +2 -0
- data/app/models/neofiles/file.rb +32 -134
- data/lib/neofiles.rb +2 -13
- data/lib/neofiles/version.rb +1 -1
- metadata +35 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3a3e40bfe2629b65d69615621cbcdc37ab95e20
|
4
|
+
data.tar.gz: 7f259aec163ff50fc5669735f4477e3c058cd942
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f6faca2b60cb0d6cb706ba969d729b2b25146a8eaeaad7dc937e72aa74a5fa2119ff424f27660b477d1eacca2a716b5e2c59bd9d0b36fc0c6c30fed7433cb47
|
7
|
+
data.tar.gz: 63bb20c3acf34a8e337bb9097454577c46d045de915f5948c810cbb9f38b45c225d08b027d945dbba73ec3dbde29ccff1216cf4769c604ac6e586e614570176d
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Neofiles::DataStore::Mongo::FileHelper
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
has_many :chunks, dependent: :destroy, order: [:n, :asc], class_name: 'Neofiles::FileChunk'
|
6
|
+
field :chunk_size, type: Integer, default: Neofiles::DataStore::Mongo::DEFAULT_CHUNK_SIZE
|
7
|
+
validates :chunk_size, presence: true
|
8
|
+
|
9
|
+
def self.copy_from_mongo_to_amazon_s3(ids)
|
10
|
+
ids.each do |id|
|
11
|
+
begin
|
12
|
+
mongo_object = Neofiles::DataStore::Mongo.find id
|
13
|
+
amazon_object = Neofiles::DataStore::AmazonS3.find(id) rescue nil
|
14
|
+
Neofiles::DataStore::AmazonS3.new(id).write(mongo_object.data) unless amazon_object
|
15
|
+
rescue Neofiles::DataStore::NotFoundException
|
16
|
+
next
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Module for storing and reading files from Amazon S3
|
2
|
+
# If you want to work with amazon s3 you need set values for the following parameters in your config file
|
3
|
+
# amazon_s3_region - the AWS region to connect to. The region is used to construct the client endpoint.
|
4
|
+
# amazon_s3_api, amazon_s3_secret - used to set credentials statically
|
5
|
+
# bucket_name - storage name in amazon_s3. Bucket must have a name that conforms to the naming requirements for non-US Standard regions.
|
6
|
+
# http://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-s3-bucket-naming-requirements.html
|
7
|
+
# File will be named as id of the Neofiles::File object
|
8
|
+
|
9
|
+
require 'aws-sdk'
|
10
|
+
|
11
|
+
class Neofiles::DataStore::AmazonS3
|
12
|
+
|
13
|
+
def self.bucket_name
|
14
|
+
Rails.application.config.neofiles.amazon_s3_bucket
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.find(id)
|
18
|
+
s3_object = new(id)
|
19
|
+
if s3_object.data
|
20
|
+
s3_object
|
21
|
+
else
|
22
|
+
raise Neofiles::DataStore::NotFoundException
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
attr_reader :id, :data, :length, :md5
|
29
|
+
|
30
|
+
def initialize(id)
|
31
|
+
@id = id
|
32
|
+
end
|
33
|
+
|
34
|
+
def data
|
35
|
+
@data ||= client.get_object(
|
36
|
+
bucket: bucket_name,
|
37
|
+
key: s3_key
|
38
|
+
).body.read
|
39
|
+
rescue Aws::S3::Errors::ServiceError
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def length
|
44
|
+
@length ||= data.length
|
45
|
+
end
|
46
|
+
|
47
|
+
def md5
|
48
|
+
@md5 ||= begin
|
49
|
+
md5 = Digest::MD5.new
|
50
|
+
md5 << data
|
51
|
+
md5.hexdigest
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write(data)
|
56
|
+
if data.is_a? Tempfile
|
57
|
+
data.flush
|
58
|
+
data.rewind
|
59
|
+
data = data.read
|
60
|
+
end
|
61
|
+
|
62
|
+
client.put_object(
|
63
|
+
body: data,
|
64
|
+
bucket: bucket_name,
|
65
|
+
key: s3_key
|
66
|
+
)
|
67
|
+
@data = data
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def s3_key
|
75
|
+
object_id = @id.to_s
|
76
|
+
object_id[0..1] + '/' + object_id[2..4] + '/' + object_id
|
77
|
+
end
|
78
|
+
|
79
|
+
def bucket_name
|
80
|
+
self.class.bucket_name
|
81
|
+
end
|
82
|
+
|
83
|
+
def client
|
84
|
+
@client ||= Aws::S3::Client.new(
|
85
|
+
region: Rails.application.config.neofiles.amazon_s3_region,
|
86
|
+
credentials: Aws::Credentials.new(
|
87
|
+
Rails.application.config.neofiles.amazon_s3_api,
|
88
|
+
Rails.application.config.neofiles.amazon_s3_secret
|
89
|
+
)
|
90
|
+
)
|
91
|
+
rescue Aws::S3::Errors::ServiceError
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
class Neofiles::DataStore::Mongo
|
2
|
+
|
3
|
+
DEFAULT_CHUNK_SIZE = Rails.application.config.neofiles.mongo_default_chunk_size
|
4
|
+
|
5
|
+
def self.chunks(id)
|
6
|
+
Neofiles::FileChunk.where(file_id: id).order_by(n: :asc)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.find(id)
|
10
|
+
if chunks(id).any?
|
11
|
+
new(id)
|
12
|
+
else
|
13
|
+
raise Neofiles::DataStore::NotFoundException
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
attr_reader :id, :data, :length, :md5
|
20
|
+
|
21
|
+
def initialize(id)
|
22
|
+
@id = id
|
23
|
+
end
|
24
|
+
|
25
|
+
def data
|
26
|
+
@data ||= chunks.pluck(:data).map(&:data).join
|
27
|
+
end
|
28
|
+
|
29
|
+
def length
|
30
|
+
@length ||= data.length
|
31
|
+
end
|
32
|
+
|
33
|
+
def md5
|
34
|
+
@md5 ||= begin
|
35
|
+
md5 = Digest::MD5.new
|
36
|
+
md5 << data
|
37
|
+
md5.hexdigest
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def write(data)
|
42
|
+
data_buf = []
|
43
|
+
md5 = Digest::MD5.new
|
44
|
+
length, n = 0, 0
|
45
|
+
|
46
|
+
reading(data) do |io|
|
47
|
+
chunking(io, DEFAULT_CHUNK_SIZE) do |buf|
|
48
|
+
md5 << buf
|
49
|
+
data_buf << buf
|
50
|
+
length += buf.size
|
51
|
+
chunk = chunks.build file_id: id
|
52
|
+
chunk.data = binary_for buf
|
53
|
+
chunk.n = n
|
54
|
+
n += 1
|
55
|
+
chunk.save!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
@data = data_buf.join
|
60
|
+
@length = length
|
61
|
+
@md5 = md5.hexdigest
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def chunks
|
69
|
+
self.class.chunks id
|
70
|
+
end
|
71
|
+
|
72
|
+
# Yield block with IO stream made from input arg, which can be file name or other IO readable object.
|
73
|
+
def reading(arg, &block)
|
74
|
+
if arg.respond_to?(:read)
|
75
|
+
rewind(arg) do |io|
|
76
|
+
block.call(io)
|
77
|
+
end
|
78
|
+
else
|
79
|
+
open(arg.to_s) do |io|
|
80
|
+
block.call(io)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Split IO stream by chunks chunk_size bytes each and yield each chunk in block.
|
86
|
+
def chunking(io, chunk_size, &block)
|
87
|
+
if io.method(:read).arity == 0
|
88
|
+
data = io.read
|
89
|
+
i = 0
|
90
|
+
loop do
|
91
|
+
offset = i * chunk_size
|
92
|
+
length = i + chunk_size < data.size ? chunk_size : data.size - offset
|
93
|
+
|
94
|
+
break if offset >= data.size
|
95
|
+
|
96
|
+
buf = data[offset, length]
|
97
|
+
block.call(buf)
|
98
|
+
i += 1
|
99
|
+
end
|
100
|
+
else
|
101
|
+
while buf = io.read(chunk_size)
|
102
|
+
block.call(buf)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Construct Mongoid binary object from string of bytes.
|
108
|
+
def binary_for(*buf)
|
109
|
+
BSON::Binary.new buf.join, :generic
|
110
|
+
end
|
111
|
+
|
112
|
+
# Yield IO-like argument to block rewinding it first, if possible.
|
113
|
+
def rewind(io, &block)
|
114
|
+
begin
|
115
|
+
pos = io.pos
|
116
|
+
io.flush
|
117
|
+
io.rewind
|
118
|
+
rescue
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
begin
|
123
|
+
block.call(io)
|
124
|
+
ensure
|
125
|
+
begin
|
126
|
+
io.pos = pos
|
127
|
+
rescue
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/app/models/neofiles/file.rb
CHANGED
@@ -44,74 +44,36 @@ class Neofiles::File
|
|
44
44
|
|
45
45
|
include Mongoid::Document
|
46
46
|
include Mongoid::Timestamps
|
47
|
+
include Neofiles::DataStore::Mongo::FileHelper
|
47
48
|
|
48
49
|
store_in collection: Rails.application.config.neofiles.mongo_files_collection, client: Rails.application.config.neofiles.mongo_client
|
49
50
|
|
50
|
-
has_many :chunks, dependent: :destroy, order: [:n, :asc], class_name: 'Neofiles::FileChunk'
|
51
|
-
|
52
|
-
DEFAULT_CHUNK_SIZE = Rails.application.config.neofiles.mongo_default_chunk_size
|
53
|
-
|
54
51
|
field :filename, type: String
|
55
52
|
field :content_type, type: String
|
56
53
|
field :length, type: Integer, default: 0
|
57
|
-
field :chunk_size, type: Integer, default: DEFAULT_CHUNK_SIZE
|
58
54
|
field :md5, type: String, default: Digest::MD5.hexdigest('')
|
59
55
|
field :description, type: String
|
60
56
|
field :owner_type, type: String
|
61
57
|
field :owner_id, type: String
|
62
58
|
field :is_deleted, type: Mongoid::Boolean
|
63
59
|
|
64
|
-
validates :filename, :length, :chunk_size, :md5, presence: true
|
65
|
-
|
66
60
|
before_save :save_file
|
67
61
|
after_save :nullify_unpersisted_file
|
68
62
|
|
69
|
-
|
70
|
-
|
71
|
-
# Yield block for each chunk.
|
72
|
-
def each(&block)
|
73
|
-
chunks.all.order_by([:n, :asc]).each do |chunk|
|
74
|
-
block.call(chunk.to_s)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# Get a portion of chunks, either via Range of Fixnum (length).
|
79
|
-
def slice(*args)
|
80
|
-
case args.first
|
81
|
-
when Range
|
82
|
-
range = args.first
|
83
|
-
first_chunk = (range.min / chunk_size).floor
|
84
|
-
last_chunk = (range.max / chunk_size).ceil
|
85
|
-
offset = range.min % chunk_size
|
86
|
-
length = range.max - range.min + 1
|
87
|
-
when Fixnum
|
88
|
-
start = args.first
|
89
|
-
start = self.length + start if start < 0
|
90
|
-
length = args.size == 2 ? args.last : 1
|
91
|
-
first_chunk = (start / chunk_size).floor
|
92
|
-
last_chunk = ((start + length) / chunk_size).ceil
|
93
|
-
offset = start % chunk_size
|
94
|
-
end
|
95
|
-
|
96
|
-
data = ''
|
97
|
-
|
98
|
-
chunks.where(n: first_chunk..last_chunk).order_by(n: :asc).each do |chunk|
|
99
|
-
data << chunk
|
100
|
-
end
|
101
|
-
|
102
|
-
data[offset, length]
|
103
|
-
end
|
104
|
-
|
105
63
|
# Chunks bytes concatenated, that is the whole file content.
|
106
64
|
def data
|
107
|
-
|
108
|
-
|
109
|
-
|
65
|
+
self.class.read_data_stores.each do |store|
|
66
|
+
begin
|
67
|
+
return store.find(id).data
|
68
|
+
rescue Neofiles::DataStore::NotFoundException
|
69
|
+
next
|
70
|
+
end
|
71
|
+
end
|
110
72
|
end
|
111
73
|
|
112
74
|
# Encode bytes in base64.
|
113
75
|
def base64
|
114
|
-
Array(
|
76
|
+
Array(data).pack('m')
|
115
77
|
end
|
116
78
|
|
117
79
|
# Encode bytes id data uri.
|
@@ -120,18 +82,6 @@ class Neofiles::File
|
|
120
82
|
"data:#{content_type};base64,#{data}"
|
121
83
|
end
|
122
84
|
|
123
|
-
# Bytes as chunks array, if block is given — yield it.
|
124
|
-
def bytes(&block)
|
125
|
-
if block
|
126
|
-
each { |data| block.call(data) }
|
127
|
-
length
|
128
|
-
else
|
129
|
-
bytes = []
|
130
|
-
each { |data| bytes.push(*data) }
|
131
|
-
bytes
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
85
|
|
136
86
|
|
137
87
|
attr_reader :file
|
@@ -159,26 +109,17 @@ class Neofiles::File
|
|
159
109
|
# File length and md5 hash are computed automatically.
|
160
110
|
def save_file
|
161
111
|
if @file
|
162
|
-
self.
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
chunk = self.chunks.build
|
172
|
-
chunk.data = self.class.binary_for(buf)
|
173
|
-
chunk.n = n
|
174
|
-
n += 1
|
175
|
-
chunk.save!
|
176
|
-
self.chunks.push(chunk)
|
112
|
+
self.class.write_data_stores.each do |store|
|
113
|
+
begin
|
114
|
+
data_store_object = store.new id
|
115
|
+
data_store_object.write @file
|
116
|
+
self.length = data_store_object.length
|
117
|
+
self.md5 = data_store_object.md5
|
118
|
+
rescue => ex
|
119
|
+
notify_airbrake(ex) if defined? notify_airbrake
|
120
|
+
next
|
177
121
|
end
|
178
122
|
end
|
179
|
-
|
180
|
-
self.length = length
|
181
|
-
self.md5 = md5.hexdigest
|
182
123
|
end
|
183
124
|
end
|
184
125
|
|
@@ -193,46 +134,6 @@ class Neofiles::File
|
|
193
134
|
template.neofiles_link self, nil, target: '_blank'
|
194
135
|
end
|
195
136
|
|
196
|
-
# Yield block with IO stream made from input arg, which can be file name or other IO readable object.
|
197
|
-
def self.reading(arg, &block)
|
198
|
-
if arg.respond_to?(:read)
|
199
|
-
self.rewind(arg) do |io|
|
200
|
-
block.call(io)
|
201
|
-
end
|
202
|
-
else
|
203
|
-
open(arg.to_s) do |io|
|
204
|
-
block.call(io)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Split IO stream by chunks chunk_size bytes each and yield each chunk in block.
|
210
|
-
def self.chunking(io, chunk_size, &block)
|
211
|
-
if io.method(:read).arity == 0
|
212
|
-
data = io.read
|
213
|
-
i = 0
|
214
|
-
loop do
|
215
|
-
offset = i * chunk_size
|
216
|
-
length = i + chunk_size < data.size ? chunk_size : data.size - offset
|
217
|
-
|
218
|
-
break if offset >= data.size
|
219
|
-
|
220
|
-
buf = data[offset, length]
|
221
|
-
block.call(buf)
|
222
|
-
i += 1
|
223
|
-
end
|
224
|
-
else
|
225
|
-
while buf = io.read(chunk_size)
|
226
|
-
block.call(buf)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
# Construct Mongoid binary object from string of bytes.
|
232
|
-
def self.binary_for(*buf)
|
233
|
-
BSON::Binary.new(buf.join, :generic)
|
234
|
-
end
|
235
|
-
|
236
137
|
# Try different methods to extract file name or path from argument object.
|
237
138
|
def self.extract_basename(object)
|
238
139
|
filename = nil
|
@@ -300,24 +201,21 @@ class Neofiles::File
|
|
300
201
|
class_by_file_name(extract_basename(file_object))
|
301
202
|
end
|
302
203
|
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
pos = io.pos
|
307
|
-
io.flush
|
308
|
-
io.rewind
|
309
|
-
rescue
|
310
|
-
nil
|
311
|
-
end
|
204
|
+
def self.read_data_stores
|
205
|
+
get_stores_class_name Rails.application.config.neofiles.read_data_stores
|
206
|
+
end
|
312
207
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
208
|
+
def self.write_data_stores
|
209
|
+
get_stores_class_name Rails.application.config.neofiles.write_data_stores
|
210
|
+
end
|
211
|
+
|
212
|
+
# return array with names for each store
|
213
|
+
def self.get_stores_class_name(stores)
|
214
|
+
if stores.is_a?(Array)
|
215
|
+
stores.map { |store| Neofiles::DataStore.const_get(store.camelize) }
|
216
|
+
else
|
217
|
+
get_stores_class_name [stores]
|
321
218
|
end
|
322
219
|
end
|
220
|
+
|
323
221
|
end
|
data/lib/neofiles.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'neofiles/engine'
|
2
|
+
require 'aspect_ratio'
|
2
3
|
|
3
4
|
module Neofiles
|
4
5
|
# Attach Neofiles specific routes in your routes.rb file:
|
@@ -34,8 +35,6 @@ module Neofiles
|
|
34
35
|
# width, height - max width and height after resize
|
35
36
|
# resize_options - {crop: '1'/'0'}, @see Neofiles::ImagesController#show
|
36
37
|
#
|
37
|
-
# Can call ImageMagick.
|
38
|
-
#
|
39
38
|
def resized_image_dimensions(image_file, width, height, resize_options)
|
40
39
|
# dimensions are equal to requested ones if cropping
|
41
40
|
return width, height if crop_requested? resize_options
|
@@ -58,17 +57,7 @@ module Neofiles
|
|
58
57
|
# image fits into requested dimensions, no resizing will occur
|
59
58
|
return image_file_width, image_file_height if image_file_width <= width && image_file_height <= height
|
60
59
|
|
61
|
-
|
62
|
-
command = MiniMagick::CommandBuilder.new(:convert) # convert input file...
|
63
|
-
command.size([image_file_width, image_file_height].join 'x') # with the given dimensions...
|
64
|
-
command.xc('white') # and filled with whites...
|
65
|
-
command.resize([width, height].join 'x') # to fit in the given rectangle...
|
66
|
-
command.push('info:-') # return info about the resulting file
|
67
|
-
|
68
|
-
# ... and send it to ImageMagick
|
69
|
-
# the result will be: xc:white XC 54x100 54x100+0+0 16-bit DirectClass 0.070u 0:00.119
|
70
|
-
# extract dimensions and return them as array of integers
|
71
|
-
MiniMagick::Image.new(nil, nil).run(command).match(/ (\d+)x(\d+) /).values_at(1, 2).map(&:to_i)
|
60
|
+
AspectRatio.resize(image_file_width, image_file_height, width, height).map(&:to_i)
|
72
61
|
|
73
62
|
rescue
|
74
63
|
nil
|
data/lib/neofiles/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neofiles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Konanykhin Ilya
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - '='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: 0.2.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: aws-sdk
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: aspect_ratio
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description: 'Library for managing files: creating & storing, linking to file owners,
|
84
112
|
serving files from MongoDB'
|
85
113
|
email:
|
@@ -106,6 +134,11 @@ files:
|
|
106
134
|
- app/controllers/neofiles/files_controller.rb
|
107
135
|
- app/controllers/neofiles/images_controller.rb
|
108
136
|
- app/helpers/neofiles/neofiles_helper.rb
|
137
|
+
- app/models/concerns/neofiles/data_store/mongo/file_helper.rb
|
138
|
+
- app/models/neofiles/data_store.rb
|
139
|
+
- app/models/neofiles/data_store/amazon_s3.rb
|
140
|
+
- app/models/neofiles/data_store/mongo.rb
|
141
|
+
- app/models/neofiles/data_store/not_found_exception.rb
|
109
142
|
- app/models/neofiles/file.rb
|
110
143
|
- app/models/neofiles/file_chunk.rb
|
111
144
|
- app/models/neofiles/image.rb
|