el_finder_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 +7 -0
- data/.editorconfig +12 -0
- data/.gitignore +36 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +37 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/el_finder_s3.gemspec +36 -0
- data/lib/el_finder_s3.rb +14 -0
- data/lib/el_finder_s3/action.rb +32 -0
- data/lib/el_finder_s3/adapter.rb +222 -0
- data/lib/el_finder_s3/base64.rb +24 -0
- data/lib/el_finder_s3/cache_connector.rb +27 -0
- data/lib/el_finder_s3/connector.rb +676 -0
- data/lib/el_finder_s3/image.rb +30 -0
- data/lib/el_finder_s3/mime_type.rb +83 -0
- data/lib/el_finder_s3/pathname.rb +250 -0
- data/lib/el_finder_s3/railties.rb +7 -0
- data/lib/el_finder_s3/s3_connector.rb +89 -0
- data/lib/el_finder_s3/s3_pathname.rb +179 -0
- data/lib/el_finder_s3/version.rb +3 -0
- metadata +126 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'shellwords'
|
3
|
+
require 'image_size'
|
4
|
+
|
5
|
+
module ElFinderS3
|
6
|
+
|
7
|
+
# Represents default image handler.
|
8
|
+
# It uses *mogrify* to resize images and *convert* to create thumbnails.
|
9
|
+
class Image
|
10
|
+
|
11
|
+
def self.size(pathname)
|
12
|
+
return nil unless File.exist?(pathname)
|
13
|
+
s = ::ImageSize.new(File.open(pathname)).size.to_s
|
14
|
+
s = nil if s.empty?
|
15
|
+
return s
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.resize(pathname, options = {})
|
19
|
+
return nil unless File.exist?(pathname)
|
20
|
+
system( ::Shellwords.join(['mogrify', '-resize', "#{options[:width]}x#{options[:height]}!", pathname.to_s]) )
|
21
|
+
end # of self.resize
|
22
|
+
|
23
|
+
def self.thumbnail(src, dst, options = {})
|
24
|
+
return nil unless File.exist?(src)
|
25
|
+
system( ::Shellwords.join(['convert', '-resize', "#{options[:width]}x#{options[:height]}", '-background', 'white', '-gravity', 'center', '-extent', "#{options[:width]}x#{options[:height]}", src.to_s, dst.to_s]) )
|
26
|
+
end # of self.resize
|
27
|
+
|
28
|
+
end # of class Image
|
29
|
+
|
30
|
+
end # of module ElFinderS3
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module ElFinderS3
|
2
|
+
|
3
|
+
# Represents default MIME types recognizer.
|
4
|
+
class MimeType
|
5
|
+
|
6
|
+
# File extension to mime type mapping.
|
7
|
+
TYPES = {
|
8
|
+
'ai' => 'application/postscript',
|
9
|
+
'eps' => 'application/postscript',
|
10
|
+
'exe' => 'application/octet-stream',
|
11
|
+
'doc' => 'application/vnd.ms-word',
|
12
|
+
'xls' => 'application/vnd.ms-excel',
|
13
|
+
'ppt' => 'application/vnd.ms-powerpoint',
|
14
|
+
'pps' => 'application/vnd.ms-powerpoint',
|
15
|
+
'pdf' => 'application/pdf',
|
16
|
+
'xml' => 'application/xml',
|
17
|
+
'odt' => 'application/vnd.oasis.opendocument.text',
|
18
|
+
'swf' => 'application/x-shockwave-flash',
|
19
|
+
# archives
|
20
|
+
'gz' => 'application/x-gzip',
|
21
|
+
'tgz' => 'application/x-gzip',
|
22
|
+
'bz' => 'application/x-bzip2',
|
23
|
+
'bz2' => 'application/x-bzip2',
|
24
|
+
'tbz' => 'application/x-bzip2',
|
25
|
+
'zip' => 'application/zip',
|
26
|
+
'rar' => 'application/x-rar',
|
27
|
+
'tar' => 'application/x-tar',
|
28
|
+
'7z' => 'application/x-7z-compressed',
|
29
|
+
# texts
|
30
|
+
'txt' => 'text/plain',
|
31
|
+
'php' => 'text/x-php',
|
32
|
+
'html' => 'text/html',
|
33
|
+
'htm' => 'text/html',
|
34
|
+
'js' => 'text/javascript',
|
35
|
+
'css' => 'text/css',
|
36
|
+
'rtf' => 'text/rtf',
|
37
|
+
'rtfd' => 'text/rtfd',
|
38
|
+
'py' => 'text/x-python',
|
39
|
+
'java' => 'text/x-java-source',
|
40
|
+
'rb' => 'text/x-ruby',
|
41
|
+
'sh' => 'text/x-shellscript',
|
42
|
+
'pl' => 'text/x-perl',
|
43
|
+
'sql' => 'text/x-sql',
|
44
|
+
# images
|
45
|
+
'bmp' => 'image/x-ms-bmp',
|
46
|
+
'jpg' => 'image/jpeg',
|
47
|
+
'jpeg' => 'image/jpeg',
|
48
|
+
'gif' => 'image/gif',
|
49
|
+
'png' => 'image/png',
|
50
|
+
'tif' => 'image/tiff',
|
51
|
+
'tiff' => 'image/tiff',
|
52
|
+
'tga' => 'image/x-targa',
|
53
|
+
'psd' => 'image/vnd.adobe.photoshop',
|
54
|
+
# audio
|
55
|
+
'mp3' => 'audio/mpeg',
|
56
|
+
'mid' => 'audio/midi',
|
57
|
+
'ogg' => 'audio/ogg',
|
58
|
+
'mp4a' => 'audio/mp4',
|
59
|
+
'wav' => 'audio/wav',
|
60
|
+
'wma' => 'audio/x-ms-wma',
|
61
|
+
# video
|
62
|
+
'avi' => 'video/x-msvideo',
|
63
|
+
'dv' => 'video/x-dv',
|
64
|
+
'mp4' => 'video/mp4',
|
65
|
+
'mpeg' => 'video/mpeg',
|
66
|
+
'mpg' => 'video/mpeg',
|
67
|
+
'mov' => 'video/quicktime',
|
68
|
+
'wm' => 'video/x-ms-wmv',
|
69
|
+
'flv' => 'video/x-flv',
|
70
|
+
'mkv' => 'video/x-matroska'
|
71
|
+
}
|
72
|
+
|
73
|
+
# Gets MIME type fort specified path.
|
74
|
+
# @param [::Pathname, String] pathname Path to recognize its MIME type.
|
75
|
+
# @return [String] MIME type if known; 'unknown/unknown' otherwise.
|
76
|
+
def self.for(pathname)
|
77
|
+
pathname = ::Pathname.new(pathname) if pathname.is_a?(String)
|
78
|
+
TYPES[pathname.extname.downcase[1..-1]] || 'application/octet-stream'
|
79
|
+
end # of for
|
80
|
+
|
81
|
+
end # of class MimeType
|
82
|
+
|
83
|
+
end # of module ElFinderS3
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module ElFinderS3
|
5
|
+
|
6
|
+
class Pathname
|
7
|
+
attr_reader :root, :path, :adapter
|
8
|
+
|
9
|
+
#
|
10
|
+
def initialize(adapter_or_root, path = '.')
|
11
|
+
@adapter = adapter_or_root.is_a?(ElFinderS3::Pathname) ? adapter_or_root.adapter : adapter_or_root
|
12
|
+
|
13
|
+
@root = path.is_a?(ElFinderS3::Pathname) ? path.root : S3Pathname.new(@adapter, '/')
|
14
|
+
|
15
|
+
if path.is_a?(ElFinderS3::Pathname)
|
16
|
+
@path = path.path
|
17
|
+
elsif path.is_a?(ElFinderS3::S3Pathname)
|
18
|
+
@path = path
|
19
|
+
else
|
20
|
+
@path = S3Pathname.new(@adapter, path)
|
21
|
+
end
|
22
|
+
if absolute?
|
23
|
+
if @path.cleanpath.to_s.start_with?(@root.to_s)
|
24
|
+
@path = S3Pathname.new(@adapter, @path.to_s.slice((@root.to_s.length)..-1), @path.attrs)
|
25
|
+
elsif @path.cleanpath.to_s.start_with?(@root.realpath.to_s)
|
26
|
+
@path = S3Pathname.new(@adapter, @path.to_s.slice((@root.realpath.to_s.length)..-1), @path.attrs)
|
27
|
+
else
|
28
|
+
raise SecurityError, "Absolute paths are not allowed"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
raise SecurityError, "Paths outside the root are not allowed" if outside_of_root?
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# of initialize
|
36
|
+
|
37
|
+
def type(type)
|
38
|
+
@type = type
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
def +(other)
|
43
|
+
if other.is_a? ::ElFinderS3::Pathname
|
44
|
+
other = other.path
|
45
|
+
end
|
46
|
+
self.class.new(@adapter, @path + other)
|
47
|
+
end
|
48
|
+
|
49
|
+
# of +
|
50
|
+
|
51
|
+
#
|
52
|
+
def is_root?
|
53
|
+
@path.to_s == '.'
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
def absolute?
|
58
|
+
@path.absolute?
|
59
|
+
end
|
60
|
+
|
61
|
+
# of absolute?
|
62
|
+
|
63
|
+
#
|
64
|
+
def relative?
|
65
|
+
@path.relative?
|
66
|
+
end
|
67
|
+
|
68
|
+
# of relative?
|
69
|
+
|
70
|
+
#
|
71
|
+
def outside_of_root?
|
72
|
+
!cleanpath.to_s.start_with?(@root.to_s)
|
73
|
+
end
|
74
|
+
|
75
|
+
# of outside_of_root?
|
76
|
+
|
77
|
+
#
|
78
|
+
def fullpath
|
79
|
+
@fullpath ||= (@path.nil? ? @root : @root + @path)
|
80
|
+
b = @path.nil? ? @root : @root + @path
|
81
|
+
return @fullpath
|
82
|
+
end
|
83
|
+
|
84
|
+
# of fullpath
|
85
|
+
|
86
|
+
#
|
87
|
+
def cleanpath
|
88
|
+
fullpath.cleanpath
|
89
|
+
end
|
90
|
+
|
91
|
+
# of cleanpath
|
92
|
+
|
93
|
+
#
|
94
|
+
def realpath
|
95
|
+
fullpath.realpath
|
96
|
+
end
|
97
|
+
|
98
|
+
# of realpath
|
99
|
+
|
100
|
+
#
|
101
|
+
def basename(*args)
|
102
|
+
@path.basename(*args)
|
103
|
+
end
|
104
|
+
|
105
|
+
# of basename
|
106
|
+
|
107
|
+
#
|
108
|
+
def basename_sans_extension
|
109
|
+
@path.basename(@path.extname)
|
110
|
+
end
|
111
|
+
|
112
|
+
# of basename
|
113
|
+
|
114
|
+
#
|
115
|
+
def basename(*args)
|
116
|
+
@path.basename(*args)
|
117
|
+
end
|
118
|
+
|
119
|
+
# of basename
|
120
|
+
|
121
|
+
#
|
122
|
+
def dirname
|
123
|
+
self.class.new(@adapter, @path.dirname)
|
124
|
+
end
|
125
|
+
|
126
|
+
# of basename
|
127
|
+
|
128
|
+
#
|
129
|
+
def extname
|
130
|
+
@path.nil? ? '' : @path.extname
|
131
|
+
end
|
132
|
+
|
133
|
+
# of extname
|
134
|
+
|
135
|
+
#
|
136
|
+
def to_s
|
137
|
+
cleanpath.to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
def to_prefix_s
|
141
|
+
prefix_s = cleanpath.to_s
|
142
|
+
if prefix_s == '/'
|
143
|
+
return ''
|
144
|
+
elsif prefix_s[0] == '/'
|
145
|
+
prefix_s[0] = ''
|
146
|
+
end
|
147
|
+
|
148
|
+
if prefix_s[prefix_s.size-1] != '/'
|
149
|
+
prefix_s = prefix_s + '/'
|
150
|
+
end
|
151
|
+
return prefix_s
|
152
|
+
end
|
153
|
+
|
154
|
+
# of to_s
|
155
|
+
alias_method :to_str, :to_s
|
156
|
+
|
157
|
+
#
|
158
|
+
def child_directories(with_directory=true)
|
159
|
+
adapter.children(self, with_directory).select { |child| child.directory? }.map { |e| self.class.new(@adapter, e) }
|
160
|
+
end
|
161
|
+
|
162
|
+
#
|
163
|
+
def files(with_directory=true)
|
164
|
+
adapter.children(self, with_directory).select { |child| child.file? }.map { |e| self.class.new(@adapter, e) }
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
#
|
169
|
+
def children(with_directory=true)
|
170
|
+
adapter.children(self, with_directory).map { |e| self.class.new(@adapter, e) }
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
def touch(options = {})
|
175
|
+
adapter.touch(cleanpath, options)
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
def relative_to(other)
|
180
|
+
@path.relative_path_from(other)
|
181
|
+
end
|
182
|
+
|
183
|
+
#
|
184
|
+
def unique
|
185
|
+
return self.dup unless fullpath.file?
|
186
|
+
copy = 1
|
187
|
+
begin
|
188
|
+
new_file = self.class.new(@adapter, dirname + "#{basename_sans_extension} #{copy}#{extname}")
|
189
|
+
copy += 1
|
190
|
+
end while new_file.exist?
|
191
|
+
new_file
|
192
|
+
end
|
193
|
+
|
194
|
+
# of unique
|
195
|
+
|
196
|
+
#
|
197
|
+
def duplicate
|
198
|
+
_basename = basename_sans_extension
|
199
|
+
copy = 1
|
200
|
+
if _basename.to_s =~ /^(.*) copy (\d+)$/
|
201
|
+
_basename = $1
|
202
|
+
copy = $2.to_i
|
203
|
+
end
|
204
|
+
begin
|
205
|
+
new_file = self.class.new(@adapter, dirname + "#{_basename} copy #{copy}#{extname}")
|
206
|
+
copy += 1
|
207
|
+
end while new_file.exist?
|
208
|
+
new_file
|
209
|
+
end
|
210
|
+
|
211
|
+
# of duplicate
|
212
|
+
|
213
|
+
#
|
214
|
+
def rename(to)
|
215
|
+
to = self.class.new(@adapter, to)
|
216
|
+
realpath.rename(to.fullpath.to_s)
|
217
|
+
to
|
218
|
+
end
|
219
|
+
|
220
|
+
# of rename
|
221
|
+
|
222
|
+
{
|
223
|
+
'directory?' => {:path => 'realpath', :rescue => true},
|
224
|
+
'exist?' => {:path => 'realpath', :rescue => true},
|
225
|
+
'file?' => {:path => 'realpath', :rescue => true},
|
226
|
+
'ftype' => {:path => 'realpath', },
|
227
|
+
'mkdir' => {:path => 'fullpath', :args => '(*args)'},
|
228
|
+
'mtime' => {:path => 'realpath', },
|
229
|
+
'open' => {:path => 'fullpath', :args => '(*args, &block)'},
|
230
|
+
'read' => {:path => 'fullpath', :args => '(*args)'},
|
231
|
+
'write' => {:path => 'fullpath', :args => '(*args)'},
|
232
|
+
'readlink' => {:path => 'fullpath', },
|
233
|
+
'readable?' => {:path => 'realpath', :rescue => true},
|
234
|
+
'size' => {:path => 'realpath', },
|
235
|
+
'symlink?' => {:path => 'fullpath', },
|
236
|
+
'unlink' => {:path => 'realpath', },
|
237
|
+
'writable?' => {:path => 'realpath', :rescue => true},
|
238
|
+
}.each_pair do |meth, opts|
|
239
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
240
|
+
def #{meth}#{opts[:args]}
|
241
|
+
#{opts[:path]}.#{meth}#{opts[:args]}
|
242
|
+
#{"rescue Errno::ENOENT\nfalse" if opts[:rescue]}
|
243
|
+
end
|
244
|
+
METHOD
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
end # of class Pathname
|
249
|
+
|
250
|
+
end # of module ElFinderS3
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module ElFinderS3
|
4
|
+
class S3Connector
|
5
|
+
:s3_client
|
6
|
+
:bucket_name
|
7
|
+
|
8
|
+
def initialize(server)
|
9
|
+
Aws.config.update(
|
10
|
+
{
|
11
|
+
region: server[:region],
|
12
|
+
credentials: Aws::Credentials.new(server[:access_key_id], server[:secret_access_key])
|
13
|
+
}
|
14
|
+
)
|
15
|
+
@bucket_name = server[:bucket_name]
|
16
|
+
@s3_client = Aws::S3::Client.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param [ElFinderS3::Pathname] pathname
|
20
|
+
def ls_la(pathname, with_directory)
|
21
|
+
prefix = pathname.to_prefix_s
|
22
|
+
query = {
|
23
|
+
bucket: @bucket_name,
|
24
|
+
delimiter: '/',
|
25
|
+
encoding_type: 'url',
|
26
|
+
max_keys: 100,
|
27
|
+
prefix: prefix
|
28
|
+
}
|
29
|
+
|
30
|
+
response = @s3_client.list_objects(query)
|
31
|
+
result = []
|
32
|
+
#Files
|
33
|
+
response.contents.each { |e|
|
34
|
+
if e.key != prefix
|
35
|
+
e.key = e.key.gsub(prefix, '')
|
36
|
+
if with_directory
|
37
|
+
result.push(pathname.fullpath + ::ElFinderS3::S3Pathname.new(self, e))
|
38
|
+
else
|
39
|
+
result.push(::ElFinderS3::S3Pathname.new(self, e))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
}
|
43
|
+
#Folders
|
44
|
+
response.common_prefixes.each { |f|
|
45
|
+
if f.prefix != '' && f.prefix != prefix && f.prefix != '/'
|
46
|
+
f.prefix = f.prefix.split('/').last
|
47
|
+
result.push(pathname.fullpath + ::ElFinderS3::S3Pathname.new(self, f))
|
48
|
+
end
|
49
|
+
}
|
50
|
+
return result
|
51
|
+
end
|
52
|
+
|
53
|
+
# @param [ElFinderS3::Pathname] pathname
|
54
|
+
def exist?(pathname)
|
55
|
+
query = {
|
56
|
+
bucket: @bucket_name,
|
57
|
+
key: pathname.to_prefix_s
|
58
|
+
}
|
59
|
+
begin
|
60
|
+
@s3_client.head_object(query)
|
61
|
+
true
|
62
|
+
rescue Aws::S3::Errors::NotFound
|
63
|
+
false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def mkdir(folder_name)
|
68
|
+
begin
|
69
|
+
@s3_client.put_object(bucket: @bucket_name, key: folder_name)
|
70
|
+
true
|
71
|
+
rescue
|
72
|
+
false
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def touch(filename)
|
77
|
+
begin
|
78
|
+
@s3_client.put_object(bucket: @bucket_name, key: filename)
|
79
|
+
true
|
80
|
+
rescue
|
81
|
+
false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def store(filename, content)
|
86
|
+
@s3_client.put_object(bucket: @bucket_name, key: filename, body: content, acl: 'public-read')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|