s3browser 0.1.0 → 0.5.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 +4 -4
- data/.gitignore +0 -0
- data/.ruby-version +1 -1
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +19 -0
- data/Rakefile +0 -0
- data/Vagrantfile +1 -0
- data/lib/s3browser.rb +0 -0
- data/lib/s3browser/fetch.rb +2 -0
- data/lib/s3browser/gem_tasks.rb +0 -0
- data/lib/s3browser/plugins/es.rb +15 -12
- data/lib/s3browser/plugins/images.rb +24 -14
- data/lib/s3browser/plugins/manager.rb +30 -0
- data/lib/s3browser/policy.json +3 -3
- data/lib/s3browser/s3proxy.rb +55 -0
- data/lib/s3browser/server.rb +33 -10
- data/lib/s3browser/store.rb +20 -6
- data/lib/s3browser/version.rb +1 -1
- data/lib/s3browser/views/bucket.haml +7 -5
- data/lib/s3browser/views/column_header.haml +0 -0
- data/lib/s3browser/views/flash_messages.haml +0 -0
- data/lib/s3browser/views/index.haml +1 -1
- data/lib/s3browser/views/layout.haml +1 -2
- data/lib/s3browser/views/object.haml +39 -0
- data/lib/s3browser/worker.rb +31 -7
- data/s3browser.gemspec +0 -0
- metadata +5 -3
- data/lib/s3browser/plugins/upload.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f0b52f998b7d61530d1781fa9fde463d59aa1bc
|
4
|
+
data.tar.gz: ecafe26c558b8dfece67e41abd119855627667fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83213e2b455ea473babb63dfd34e035563554dbeb8451671e5c7b69a3729722802aeec80db15bbdfe5b2ca4761c3e18abbde63a370630b940eeb9ba0f939007c
|
7
|
+
data.tar.gz: ecd3b4f3905cec378da87d8204d88695c0c2b3699960f1841c54f8435700de3e61d261697ad7d3036288cccbbb4013014a8f89a96efc485b06ce228fe6dca109
|
data/.gitignore
CHANGED
File without changes
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3.
|
1
|
+
2.3.1
|
data/Gemfile
CHANGED
File without changes
|
data/LICENSE.txt
CHANGED
File without changes
|
data/README.md
CHANGED
@@ -10,6 +10,7 @@ This wrapper gives you a couple of killer functions:
|
|
10
10
|
* [x] Automatically update file information
|
11
11
|
* [x] Upload files
|
12
12
|
* [x] Download files
|
13
|
+
* [x] Delete files
|
13
14
|
|
14
15
|
## Installation
|
15
16
|
|
@@ -33,6 +34,7 @@ Here's an example config.ru for booting S3Browser::Server in your choice of Rack
|
|
33
34
|
|
34
35
|
```ruby
|
35
36
|
# config.ru
|
37
|
+
#\-o 0.0.0.0 -p 9292
|
36
38
|
require 's3browser/server'
|
37
39
|
run S3Browser::Server
|
38
40
|
```
|
@@ -147,6 +149,23 @@ After setting up the queue and the bucket, a policy **without** the following ac
|
|
147
149
|
* sqs:GetQueueAttributes
|
148
150
|
* sqs:SetQueueAttributes
|
149
151
|
|
152
|
+
## S3Proxy
|
153
|
+
|
154
|
+
You might not want to allow public access to your S3 bucket. To work around this, the gem provides a proxy with which the server will fetch the file from S3 and serve it to the client, caching it in between.
|
155
|
+
|
156
|
+
It's a simple Sinatra app, so can be mounted on a Rack endpoint as well:
|
157
|
+
|
158
|
+
```
|
159
|
+
# config.ru
|
160
|
+
#\-o 0.0.0.0 -p 9292
|
161
|
+
require 's3browser/server'
|
162
|
+
require 's3browser/s3proxy'
|
163
|
+
|
164
|
+
run Rack::URLMap.new('/s3' => S3Browser::S3Proxy, '/' => S3Browser::Server)
|
165
|
+
```
|
166
|
+
|
167
|
+
The above example allows you to set the `S3BROWSER_THUMBNAIL_URL` and `S3BROWSER_OBJECT_URL` environmental variables to `/s3` so that you can download and view the files from the browser.
|
168
|
+
|
150
169
|
## Development
|
151
170
|
|
152
171
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/Rakefile
CHANGED
File without changes
|
data/Vagrantfile
CHANGED
@@ -29,6 +29,7 @@ Vagrant.configure(2) do |config|
|
|
29
29
|
sudo apt-get install -y elasticsearch
|
30
30
|
sudo service elasticsearch stop
|
31
31
|
echo "ES_HEAP_SIZE=1g" | sudo tee -a /etc/default/elasticsearch
|
32
|
+
echo "network.host: 0.0.0.0" | sudo tee -a /etc/elasticsearch/elasticsearch.yml
|
32
33
|
|
33
34
|
# Dependencies / Utilities
|
34
35
|
sudo apt-get install -y screen curl git build-essential
|
data/lib/s3browser.rb
CHANGED
File without changes
|
data/lib/s3browser/fetch.rb
CHANGED
data/lib/s3browser/gem_tasks.rb
CHANGED
File without changes
|
data/lib/s3browser/plugins/es.rb
CHANGED
@@ -21,27 +21,28 @@ module S3Browser
|
|
21
21
|
# TODO Can be optimized to do a bulk index every X requests
|
22
22
|
object[:bucket] = bucket
|
23
23
|
object[:last_modified] = object[:last_modified].to_i
|
24
|
-
object[:url] = "
|
24
|
+
object[:url] = "#{object_url}/#{bucket}/#{object[:key]}"
|
25
25
|
client.index(index: index, type: 'objects', id: object[:key], body: object)
|
26
26
|
super(bucket, object)
|
27
27
|
end
|
28
28
|
|
29
|
+
def remove(bucket, key)
|
30
|
+
client.delete(index: index, type: 'objects', id: key, ignore: [404])
|
31
|
+
super(bucket, key)
|
32
|
+
end
|
33
|
+
|
29
34
|
def objects(bucket, options)
|
30
|
-
|
31
|
-
|
32
|
-
raise 'Not implemented yet'
|
33
|
-
else
|
34
|
-
result = client.search(index: index, type: 'objects', body: body)
|
35
|
-
result['hits']['hits'].map {|val| val['_source'].inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo} }
|
36
|
-
end
|
35
|
+
result = client.search(index: index, type: 'objects', body: search_body(bucket, options))
|
36
|
+
result['hits']['hits'].map {|val| val['_source'].inject({}){|memo,(k,v)| memo[k.downcase.to_sym] = v; memo} }
|
37
37
|
end
|
38
38
|
|
39
|
-
def
|
40
|
-
get(
|
39
|
+
def object(bucket, key)
|
40
|
+
result = client.get(index: index, type: 'objects', id: key)
|
41
|
+
result['_source'].inject({}){|memo,(k,v)| memo[k.downcase.to_sym] = v; memo}
|
41
42
|
end
|
42
43
|
|
43
44
|
def buckets
|
44
|
-
client.search(index: index, type: 'objects', body: {
|
45
|
+
buckets = client.search(index: index, type: 'objects', body: {
|
45
46
|
query: { match_all: {} },
|
46
47
|
size: 0,
|
47
48
|
aggregations: {
|
@@ -54,6 +55,8 @@ module S3Browser
|
|
54
55
|
}
|
55
56
|
}
|
56
57
|
})['aggregations']['buckets']['buckets'].map {|val| val['key'] }
|
58
|
+
return buckets unless buckets.empty?
|
59
|
+
super
|
57
60
|
end
|
58
61
|
|
59
62
|
def indices
|
@@ -78,7 +81,7 @@ module S3Browser
|
|
78
81
|
end
|
79
82
|
|
80
83
|
private
|
81
|
-
def
|
84
|
+
def search_body(bucket, options = {})
|
82
85
|
body = {
|
83
86
|
query: {
|
84
87
|
bool: {
|
@@ -3,26 +3,36 @@ module S3Browser
|
|
3
3
|
module StorePlugins
|
4
4
|
module Images
|
5
5
|
module InstanceMethods
|
6
|
-
def add(bucket, object)
|
7
|
-
return super(bucket, object) unless handle?(object)
|
8
|
-
# TODO Create a thumbnail and make it available
|
9
|
-
|
10
|
-
super(bucket, object)
|
11
|
-
end
|
12
|
-
|
13
6
|
def objects(bucket, options)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
url: "http://#{bucket}.s3.amazonaws.com/#{elm[:key]}",
|
7
|
+
super(bucket, options).map do |object|
|
8
|
+
object[:thumbnail] = {
|
9
|
+
url: "#{thumbnail_url}/#{bucket}/#{object[:key]}",
|
18
10
|
width: 200
|
19
|
-
} if handle?(
|
20
|
-
|
11
|
+
} if handle?(object)
|
12
|
+
object
|
21
13
|
end
|
22
14
|
end
|
23
15
|
|
16
|
+
def object(bucket, key)
|
17
|
+
object = super(bucket, key)
|
18
|
+
object[:thumbnail] = {
|
19
|
+
url: "#{thumbnail_url}/#{bucket}/#{object[:key]}",
|
20
|
+
width: 200
|
21
|
+
} if handle?(object)
|
22
|
+
object
|
23
|
+
end
|
24
|
+
|
24
25
|
def handle?(object)
|
25
|
-
object[:content_type] =~ /^image\/.*/
|
26
|
+
return (object[:content_type] =~ /^image\/.*/) unless (object[:content_type].nil? || object[:content_type] == '')
|
27
|
+
return (object[:type] =~ /^image\/.*/) unless (object[:type].nil? || object[:type] == '')
|
28
|
+
object[:key] =~ /(jpg|jpeg|png|gif|bmp)$/
|
29
|
+
end
|
30
|
+
|
31
|
+
def thumbnail_url
|
32
|
+
@thumbnail_url ||= begin
|
33
|
+
return ENV['S3BROWSER_THUMBNAIL_URL'] if ENV['S3BROWSER_THUMBNAIL_URL']
|
34
|
+
"http://s3-#{ENV['AWS_REGION']}.amazonaws.com"
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module S3Browser
|
4
|
+
class Store
|
5
|
+
module StorePlugins
|
6
|
+
module Manager
|
7
|
+
module InstanceMethods
|
8
|
+
def upload(bucket, file)
|
9
|
+
filename = file[:filename]
|
10
|
+
tempfile = file[:tempfile]
|
11
|
+
|
12
|
+
s3 = Aws::S3::Resource.new
|
13
|
+
s3.bucket(bucket).object(filename).upload_file(tempfile.path)
|
14
|
+
|
15
|
+
super(bucket, file)
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete(bucket, file)
|
19
|
+
s3 = Aws::S3::Client.new
|
20
|
+
s3.delete_object(bucket: bucket, key: file)
|
21
|
+
|
22
|
+
super(bucket, file)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
register_plugin(:manager, Manager)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/s3browser/policy.json
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
"Version": "2012-10-17",
|
3
3
|
"Statement": [
|
4
4
|
{
|
5
|
-
"Sid": "
|
5
|
+
"Sid": "S3BrowserGenerateSQS",
|
6
6
|
"Effect": "Allow",
|
7
7
|
"Principal": { "AWS": "*" },
|
8
8
|
"Action": [
|
@@ -10,8 +10,8 @@
|
|
10
10
|
],
|
11
11
|
"Resource": "SQS-queue-ARN",
|
12
12
|
"Condition": {
|
13
|
-
"ArnLike": {
|
14
|
-
"aws:SourceArn": "arn:aws:s3:*:*:bucket-name"
|
13
|
+
"ArnLike": {
|
14
|
+
"aws:SourceArn": "arn:aws:s3:*:*:bucket-name"
|
15
15
|
}
|
16
16
|
}
|
17
17
|
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
|
3
|
+
module S3Browser
|
4
|
+
class S3Proxy < Sinatra::Base
|
5
|
+
raise 'Unconfigured' unless ENV['AWS_REGION']
|
6
|
+
|
7
|
+
configure :development do
|
8
|
+
enable :logging
|
9
|
+
end
|
10
|
+
|
11
|
+
get %r{(.+)} do |filename|
|
12
|
+
read_file filename
|
13
|
+
end
|
14
|
+
|
15
|
+
helpers do
|
16
|
+
def read_file(file)
|
17
|
+
cached_file = cache_location(file)
|
18
|
+
|
19
|
+
matches = file.match(/([^\/]+)\/(.*)/)
|
20
|
+
options = {
|
21
|
+
bucket: matches[1],
|
22
|
+
key: matches[2],
|
23
|
+
}
|
24
|
+
options[:if_modified_since] = File.mtime(cached_file) if File.exists?(cached_file)
|
25
|
+
|
26
|
+
begin
|
27
|
+
s3object = s3.get_object(options, target: cached_file)
|
28
|
+
rescue Aws::S3::Errors::NotModified
|
29
|
+
options.delete(:if_modified_since)
|
30
|
+
s3object = s3.head_object(options)
|
31
|
+
rescue
|
32
|
+
halt(404)
|
33
|
+
end
|
34
|
+
send_file cached_file, file_name: File.basename(file), type: s3object.content_type
|
35
|
+
end
|
36
|
+
|
37
|
+
def cache_location(file)
|
38
|
+
matches = file.match(/([^\/]+)\/(.*)/)
|
39
|
+
"#{cache_folder}/#{matches[2]}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def cache_folder
|
43
|
+
path = '/tmp/s3proxy'
|
44
|
+
Dir.mkdir(path) unless File.exists?(path)
|
45
|
+
path
|
46
|
+
end
|
47
|
+
|
48
|
+
def s3
|
49
|
+
@s3 ||= Aws::S3::Client.new
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
run! if app_file == $0
|
54
|
+
end
|
55
|
+
end
|
data/lib/s3browser/server.rb
CHANGED
@@ -5,20 +5,24 @@ require 's3browser/store'
|
|
5
5
|
|
6
6
|
module S3Browser
|
7
7
|
class Server < Sinatra::Base
|
8
|
-
|
8
|
+
raise 'Unconfigured' unless ENV['AWS_REGION']
|
9
|
+
|
9
10
|
use Rack::Flash
|
10
11
|
|
11
12
|
class Store < S3Browser::Store
|
12
13
|
plugin :es
|
13
14
|
plugin :images
|
14
|
-
plugin :
|
15
|
+
plugin :manager
|
16
|
+
end
|
17
|
+
|
18
|
+
configure do
|
19
|
+
enable :sessions
|
20
|
+
enable :method_override
|
21
|
+
set :store, Store.new('s3browser')
|
15
22
|
end
|
16
23
|
|
17
24
|
configure :development do
|
18
|
-
set :port, 9292
|
19
|
-
set :bind, '0.0.0.0'
|
20
25
|
enable :logging
|
21
|
-
set :store, Store.new('s3browser')
|
22
26
|
end
|
23
27
|
|
24
28
|
get '/' do
|
@@ -26,19 +30,38 @@ module S3Browser
|
|
26
30
|
haml :index, locals: { title: 'S3Browser', buckets: buckets }
|
27
31
|
end
|
28
32
|
|
29
|
-
get '/:bucket' do |bucket|
|
33
|
+
get '/:bucket/?' do |bucket|
|
30
34
|
params['q'] = nil if params['q'] == ''
|
31
35
|
objects = settings.store.objects(bucket, term: params['q'], sort: params['s'], direction: params['d'])
|
32
36
|
haml :bucket, locals: { title: bucket, bucket: bucket, objects: objects, q: params['q'] }
|
33
37
|
end
|
34
38
|
|
35
|
-
|
39
|
+
get '/:bucket/:key/?' do |bucket, key|
|
40
|
+
begin
|
41
|
+
object = settings.store.object(bucket, key)
|
42
|
+
rescue
|
43
|
+
halt(404)
|
44
|
+
end
|
45
|
+
haml :object, locals: { title: key, bucket: bucket, key: key, object: object }
|
46
|
+
end
|
47
|
+
|
48
|
+
delete '/:bucket/:key/?' do |bucket, key|
|
49
|
+
begin
|
50
|
+
settings.store.delete(bucket, key)
|
51
|
+
flash[:success] = 'File deleted'
|
52
|
+
rescue StandardError => e
|
53
|
+
flash[:error] = 'Could not remove the file: ' + e.message
|
54
|
+
end
|
55
|
+
redirect back
|
56
|
+
end
|
57
|
+
|
58
|
+
post '/upload/:bucket/?' do |bucket|
|
36
59
|
if params['upload']
|
37
60
|
begin
|
38
|
-
settings.store.upload params['upload']
|
61
|
+
settings.store.upload bucket, params['upload']
|
39
62
|
flash[:success] = 'File uploaded'
|
40
|
-
rescue
|
41
|
-
flash[:error] = 'Could not upload the file'
|
63
|
+
rescue StandardError => e
|
64
|
+
flash[:error] = 'Could not upload the file: ' + e.message
|
42
65
|
end
|
43
66
|
end
|
44
67
|
redirect back
|
data/lib/s3browser/store.rb
CHANGED
@@ -71,25 +71,39 @@ module S3Browser
|
|
71
71
|
end
|
72
72
|
|
73
73
|
module InstanceMethods
|
74
|
-
def
|
74
|
+
def add(bucket, object)
|
75
|
+
nil
|
75
76
|
end
|
76
77
|
|
77
|
-
def
|
78
|
+
def remove(bucket, key)
|
78
79
|
nil
|
79
80
|
end
|
80
81
|
|
82
|
+
def upload(bucket, file)
|
83
|
+
end
|
84
|
+
|
85
|
+
def delete(bucket, file)
|
86
|
+
end
|
87
|
+
|
81
88
|
def objects(bucket, options)
|
82
89
|
s3.list_objects(bucket: bucket).contents.map do |object|
|
83
|
-
object.to_h.merge(bucket: bucket, url: "
|
90
|
+
object.to_h.merge(bucket: bucket, url: "#{object_url}/#{bucket}/#{object[:key]}")
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
87
|
-
def
|
88
|
-
|
94
|
+
def object(bucket, key)
|
95
|
+
s3.head_object(bucket: bucket, key: key)
|
89
96
|
end
|
90
97
|
|
91
98
|
def buckets
|
92
|
-
s3.list_buckets.buckets
|
99
|
+
s3.list_buckets.buckets.map {|val| val['name'] }
|
100
|
+
end
|
101
|
+
|
102
|
+
def object_url
|
103
|
+
@object_url ||= begin
|
104
|
+
return ENV['S3BROWSER_OBJECT_URL'] if ENV['S3BROWSER_OBJECT_URL']
|
105
|
+
"http://s3-#{ENV['AWS_REGION']}.amazonaws.com"
|
106
|
+
end
|
93
107
|
end
|
94
108
|
|
95
109
|
private
|
data/lib/s3browser/version.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
= bucket
|
6
6
|
.panel-body
|
7
7
|
.col-md-10
|
8
|
-
%form.form-horizontal{method: 'get', action: "/#{bucket}"}
|
8
|
+
%form.form-horizontal{method: 'get', action: url("/#{bucket}")}
|
9
9
|
.form-group
|
10
10
|
.input-group
|
11
11
|
%input.form-control{ type: 'text', name: 'q', placeholder: 'Search', value: q }
|
@@ -22,6 +22,7 @@
|
|
22
22
|
= haml :column_header, locals: { field: :key }
|
23
23
|
= haml :column_header, locals: { field: :size }
|
24
24
|
= haml :column_header, locals: { field: :content_type, field_name: 'Type' }
|
25
|
+
%th Download
|
25
26
|
= haml :column_header, locals: { field: :last_modified }
|
26
27
|
%th
|
27
28
|
Thumbnail
|
@@ -29,17 +30,18 @@
|
|
29
30
|
-objects.each do |obj|
|
30
31
|
%tr
|
31
32
|
%td
|
32
|
-
%a{
|
33
|
-
= obj[:key]
|
33
|
+
%a{ href: url("/#{bucket}/#{obj[:key]}") }= obj[:key]
|
34
34
|
%td= obj[:size]
|
35
35
|
%td= obj[:content_type]
|
36
|
+
%td
|
37
|
+
%a.btn.btn-default{ target: '_blank', href: obj[:url] } Download
|
36
38
|
%td= Time.at(obj[:last_modified]).strftime('%Y-%m-%d %H:%M:%S')
|
37
39
|
%td
|
38
40
|
-if obj[:thumbnail]
|
39
|
-
%img{ src: obj[:thumbnail][:url], width: obj[:thumbnail][:width]}
|
41
|
+
%img.img-response.center-block.img-thumbnail{ src: obj[:thumbnail][:url], width: obj[:thumbnail][:width]}
|
40
42
|
|
41
43
|
- if settings.store.respond_to? :upload
|
42
|
-
%form{ enctype: 'multipart/form-data', method: 'post', action: '/upload' }
|
44
|
+
%form{ enctype: 'multipart/form-data', method: 'post', action: '/upload/' + bucket }
|
43
45
|
#upload-modal.modal.fade{ tabindex: -1, role: 'dialog' }
|
44
46
|
.modal-dialog
|
45
47
|
.modal-content
|
File without changes
|
File without changes
|
@@ -3,7 +3,7 @@
|
|
3
3
|
%head
|
4
4
|
%meta{:charset => 'utf-8'}
|
5
5
|
%title
|
6
|
-
S3Browser
|
6
|
+
S3Browser
|
7
7
|
- if defined? title
|
8
8
|
= "- #{title}"
|
9
9
|
%meta{:name => "description", :content => ""}
|
@@ -34,6 +34,5 @@
|
|
34
34
|
|
35
35
|
/ Placed at the end of the document so the pages load faster
|
36
36
|
%script{ type: 'text/javascript', src: '//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js' }
|
37
|
-
%script{ type: 'text/javascript', src: '//maps.googleapis.com/maps/api/js?libraries=places' }
|
38
37
|
%script{ type: 'text/javascript', src: '//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js' }
|
39
38
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
.row
|
2
|
+
.col-md-12
|
3
|
+
.panel.panel-primary
|
4
|
+
.panel-heading
|
5
|
+
= "#{bucket} / #{key}"
|
6
|
+
|
7
|
+
%table.table.table-hover
|
8
|
+
%tr
|
9
|
+
%th Key
|
10
|
+
%td= object[:key]
|
11
|
+
%tr
|
12
|
+
%th Bucket
|
13
|
+
%td= object[:bucket]
|
14
|
+
%tr
|
15
|
+
%th eTag
|
16
|
+
%td= object[:etag]
|
17
|
+
%tr
|
18
|
+
%th Size
|
19
|
+
%td= object[:size]
|
20
|
+
%tr
|
21
|
+
%th Type
|
22
|
+
%td= object[:content_type]
|
23
|
+
%tr
|
24
|
+
%th Last Modified
|
25
|
+
%td= Time.at(object[:last_modified]).strftime('%Y-%m-%d %H:%M:%S')
|
26
|
+
%tr
|
27
|
+
%th Storage Class
|
28
|
+
%td= object[:storage_class]
|
29
|
+
%tr
|
30
|
+
%td.text-left
|
31
|
+
%a.btn.btn-default{ target: '_base', href: object[:url] } Download
|
32
|
+
%td.text-right
|
33
|
+
%form{ method: 'post', action: url("/#{bucket}/#{object[:key]}") }
|
34
|
+
%input{ type: 'hidden', name: '_method', value: 'delete'}
|
35
|
+
%button.btn.btn-warning{ type: 'submit', onclick: 'return confirm("This will completely remove the file.");' } Delete
|
36
|
+
-if object[:thumbnail]
|
37
|
+
.row
|
38
|
+
.col-md-12
|
39
|
+
%img.img-response.img-thumbnail.center-block{ src: object[:url] }
|
data/lib/s3browser/worker.rb
CHANGED
@@ -5,6 +5,8 @@ module S3Browser
|
|
5
5
|
class Worker
|
6
6
|
include Shoryuken::Worker
|
7
7
|
|
8
|
+
raise 'Unconfigured' unless ENV['AWS_REGION']
|
9
|
+
|
8
10
|
shoryuken_options queue: ENV['AWS_SQS_QUEUE'], body_parser: :json, auto_delete: true
|
9
11
|
|
10
12
|
class Store < S3Browser::Store
|
@@ -12,22 +14,44 @@ module S3Browser
|
|
12
14
|
plugin :images
|
13
15
|
end
|
14
16
|
|
17
|
+
def initialize
|
18
|
+
Shoryuken.logger.level = ::Logger::DEBUG if ENV['RACK_ENV'] != 'production'
|
19
|
+
end
|
20
|
+
|
15
21
|
def perform(sqs_msg, body)
|
22
|
+
Shoryuken.logger.debug body
|
23
|
+
|
16
24
|
if body['Records']
|
17
25
|
body['Records'].each do |record|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
store.add bucket, info
|
26
|
+
case record['eventName']
|
27
|
+
when 'ObjectRemoved:Delete'
|
28
|
+
remove record
|
29
|
+
when 'ObjectCreated:Put'
|
30
|
+
add record
|
31
|
+
end
|
25
32
|
end
|
26
33
|
else
|
27
34
|
raise unless body['Event'] == 's3:TestEvent'
|
28
35
|
end
|
29
36
|
end
|
30
37
|
|
38
|
+
def add(record)
|
39
|
+
bucket = record['s3']['bucket']['name']
|
40
|
+
key = record['s3']['object']['key']
|
41
|
+
|
42
|
+
info = s3.head_object({ bucket: bucket, key: key })
|
43
|
+
info = info.to_h.merge(record['s3']['object'].inject({}){|memo,(k,v)| memo[k.downcase.to_sym] = v; memo})
|
44
|
+
|
45
|
+
store.add bucket, info
|
46
|
+
end
|
47
|
+
|
48
|
+
def remove(record)
|
49
|
+
bucket = record['s3']['bucket']['name']
|
50
|
+
key = record['s3']['object']['key']
|
51
|
+
|
52
|
+
store.remove bucket, key
|
53
|
+
end
|
54
|
+
|
31
55
|
private
|
32
56
|
def store
|
33
57
|
@store ||= Store.new('s3browser')
|
data/s3browser.gemspec
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: s3browser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jurgens du Toit
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -173,8 +173,9 @@ files:
|
|
173
173
|
- lib/s3browser/gem_tasks.rb
|
174
174
|
- lib/s3browser/plugins/es.rb
|
175
175
|
- lib/s3browser/plugins/images.rb
|
176
|
-
- lib/s3browser/plugins/
|
176
|
+
- lib/s3browser/plugins/manager.rb
|
177
177
|
- lib/s3browser/policy.json
|
178
|
+
- lib/s3browser/s3proxy.rb
|
178
179
|
- lib/s3browser/server.rb
|
179
180
|
- lib/s3browser/store.rb
|
180
181
|
- lib/s3browser/version.rb
|
@@ -183,6 +184,7 @@ files:
|
|
183
184
|
- lib/s3browser/views/flash_messages.haml
|
184
185
|
- lib/s3browser/views/index.haml
|
185
186
|
- lib/s3browser/views/layout.haml
|
187
|
+
- lib/s3browser/views/object.haml
|
186
188
|
- lib/s3browser/worker.rb
|
187
189
|
- s3browser.gemspec
|
188
190
|
homepage: https://github.com/jrgns/s3browser
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'aws-sdk'
|
2
|
-
|
3
|
-
module S3Browser
|
4
|
-
class Store
|
5
|
-
module StorePlugins
|
6
|
-
module Upload
|
7
|
-
module InstanceMethods
|
8
|
-
def upload(file)
|
9
|
-
filename = file[:filename]
|
10
|
-
file = file[:tempfile]
|
11
|
-
bucket = 's3browser'
|
12
|
-
|
13
|
-
s3 = Aws::S3::Resource.new
|
14
|
-
s3.bucket(bucket).object(filename).upload_file(file.path)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
register_plugin(:upload, Upload)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|