s3_cors_fileupload 0.2.1 → 0.3.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -0
  3. data/CHANGELOG.md +10 -3
  4. data/Gemfile +11 -9
  5. data/Gemfile.lock +86 -65
  6. data/README.md +8 -4
  7. data/lib/generators/s3_cors_fileupload/install/install_generator.rb +5 -2
  8. data/lib/generators/s3_cors_fileupload/install/templates/s3_uploads_controller.rb +3 -1
  9. data/lib/generators/s3_cors_fileupload/install/templates/source_file.rb +4 -3
  10. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_download.html.erb +18 -7
  11. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_upload.html.erb +4 -4
  12. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/_template_uploaded.html.erb +17 -6
  13. data/lib/generators/s3_cors_fileupload/install/templates/views/erb/index.html.erb +1 -1
  14. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_download.html.haml +14 -4
  15. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_upload.html.haml +5 -5
  16. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/_template_uploaded.html.haml +12 -1
  17. data/lib/generators/s3_cors_fileupload/install/templates/views/haml/index.html.haml +1 -1
  18. data/lib/s3_cors_fileupload.rb +6 -0
  19. data/lib/s3_cors_fileupload/rails.rb +1 -1
  20. data/lib/s3_cors_fileupload/rails/form_helper.rb +15 -12
  21. data/lib/s3_cors_fileupload/version.rb +3 -3
  22. data/s3_cors_fileupload.gemspec +3 -4
  23. data/spec/dummy/Rakefile +0 -1
  24. data/spec/dummy/app/assets/javascripts/application.js +4 -3
  25. data/spec/dummy/app/assets/javascripts/s3_uploads.js +92 -0
  26. data/spec/dummy/app/assets/stylesheets/application.css +1 -0
  27. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  28. data/spec/dummy/app/controllers/s3_uploads_controller.rb +56 -0
  29. data/spec/dummy/app/models/source_file.rb +54 -0
  30. data/spec/dummy/app/views/layouts/application.html.erb +2 -2
  31. data/spec/dummy/app/views/s3_uploads/_template_download.html.erb +43 -0
  32. data/spec/dummy/app/views/s3_uploads/_template_upload.html.erb +36 -0
  33. data/spec/dummy/app/views/s3_uploads/_template_uploaded.html.erb +41 -0
  34. data/spec/dummy/app/views/s3_uploads/index.html.erb +41 -0
  35. data/spec/dummy/bin/bundle +3 -0
  36. data/spec/dummy/bin/rails +4 -0
  37. data/spec/dummy/bin/rake +4 -0
  38. data/spec/dummy/config.ru +1 -1
  39. data/spec/dummy/config/application.rb +2 -33
  40. data/spec/dummy/config/boot.rb +4 -9
  41. data/spec/dummy/config/environment.rb +2 -2
  42. data/spec/dummy/config/environments/development.rb +14 -19
  43. data/spec/dummy/config/environments/production.rb +40 -27
  44. data/spec/dummy/config/environments/test.rb +14 -12
  45. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  46. data/spec/dummy/config/initializers/inflections.rb +6 -5
  47. data/spec/dummy/config/initializers/secret_token.rb +7 -2
  48. data/spec/dummy/config/initializers/session_store.rb +0 -5
  49. data/spec/dummy/config/initializers/wrap_parameters.rb +6 -6
  50. data/spec/dummy/config/locales/en.yml +20 -2
  51. data/spec/dummy/config/routes.rb +27 -24
  52. data/spec/dummy/db/migrate/20131001201535_create_source_files.rb +14 -0
  53. data/spec/dummy/db/schema.rb +27 -0
  54. data/spec/dummy/public/404.html +43 -11
  55. data/spec/dummy/public/422.html +43 -11
  56. data/spec/dummy/public/500.html +43 -11
  57. data/spec/features/uploads_spec.rb +37 -0
  58. data/spec/lib/s3_cors_fileupload/rails/engine_spec.rb +8 -0
  59. data/spec/lib/s3_cors_fileupload/rails/form_helper_spec.rb +30 -0
  60. data/spec/lib/s3_cors_fileupload/rails/policy_helper_spec.rb +95 -0
  61. data/spec/s3_cors_fileupload_spec.rb +8 -4
  62. data/spec/spec_helper.rb +8 -8
  63. data/spec/support/dummy.pdf +0 -0
  64. data/vendor/assets/javascripts/s3_cors_fileupload/index.js +1 -0
  65. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload-image.js +111 -32
  66. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload-ui.js +24 -18
  67. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload-validate.js +7 -6
  68. data/vendor/assets/javascripts/s3_cors_fileupload/jquery.fileupload.js +22 -15
  69. data/vendor/assets/javascripts/s3_cors_fileupload/vendor/load-image-meta.js +137 -0
  70. data/vendor/assets/javascripts/s3_cors_fileupload/vendor/tmpl.js +8 -8
  71. data/vendor/assets/stylesheets/jquery.fileupload-ui.css.erb +2 -1
  72. metadata +56 -28
  73. data/spec/dummy/script/rails +0 -6
@@ -1,4 +1,4 @@
1
- <%= stylesheet_link_tag '//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css' %>
1
+ <%= stylesheet_link_tag '//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css' %>
2
2
 
3
3
  <div style="padding: 10px;">
4
4
  <h2>Upload file(s)</h2>
@@ -7,21 +7,31 @@
7
7
  %span.preview
8
8
  {% if (file.thumbnailUrl) { %}
9
9
  %a{:download => "{%=file.name%}", :href => "{%=file.url%}", :title => "{%=file.name%}", :"data-gallery" => ''}
10
- %img{:src => "{%=file.thumbnailUrl%}"}/
10
+ %img{:src => "{%=file.thumbnailUrl%}"}
11
11
  {% } %}
12
12
  %td
13
13
  %p.name
14
+ {% if (file.url) { %}
14
15
  %a{:href => "{%=file.url%}", :title => "{%=file.name%}", :download => "{%=file.name%}", :"data-gallery" => !"{%= file.thumbnailUrl ? ' ' : '' %}".html_safe.empty? && ''} {%=file.name%}
16
+ {% } else { %}
17
+ %span {%=file.name%}
18
+ {% } %}
15
19
  {% if (file.error) { %}
16
20
  %div
17
- %span.label.label-important Error
21
+ %span.label.label-danger Error
18
22
  {%=file.error%}
19
23
  {% } %}
20
24
  %td
21
25
  %span.size {%=o.formatFileSize(file.size)%}
22
26
  %td
23
- %button.btn.btn-danger.delete{"data-type" => "{%=file.delete_type%}", "data-url" => "{%=file.delete_url%}", "data-confirmation" => "Are you sure?", "data-xhr-fields" => !"{% if (file.delete_with_credentials) { %} {'withCredentials': true} {% } %}".blank? && "{% if (file.delete_with_credentials) { %} {'withCredentials': true} {% } %}"}
24
- %i.icon-trash.icon-white
27
+ {% if (file.deleteUrl) { %}
28
+ %button.btn.btn-danger.delete{"data-type" => "{%=file.deleteType%}", "data-url" => "{%=file.deleteUrl%}", "data-confirmation" => "Are you sure?", "data-xhr-fields" => !"{% if (file.delete_with_credentials) { %} {'withCredentials': true} {% } %}".blank? && "{% if (file.delete_with_credentials) { %} {'withCredentials': true} {% } %}"}
29
+ %i.glyphicon.glyphicon-trash
25
30
  %span Delete
26
31
  %input.toggle{:name => "delete", :type => "checkbox", :value => "1"}
32
+ {% } else { %}
33
+ %button.btn.btn-warning.cancel
34
+ %i.glyphicon.glyphicon-ban-circle
35
+ %span Cancel
36
+ {% } %}
27
37
  {% } %}
@@ -9,24 +9,24 @@
9
9
  %p.name {%=file.name%}
10
10
  {% if (file.error) { %}
11
11
  %div
12
- %span.label.label-important Error
12
+ %span.label.label-danger Error
13
13
  {%=file.error%}
14
14
  {% } %}
15
15
  %td
16
16
  %p.size {%=o.formatFileSize(file.size)%}
17
17
  {% if (!o.files.error) { %}
18
- .progress.progress-success.progress-striped.active{:role => 'progressbar', :"aria-valuemin" => '0', :"aria-valuemax" => '100', :"aria-valuenow" => '0'}
19
- .bar{:style => "width:0%;"}
18
+ .progress.progress-striped.active{:role => 'progressbar', :"aria-valuemin" => '0', :"aria-valuemax" => '100', :"aria-valuenow" => '0'}
19
+ .progress-bar.progress-bar-success{:style => "width:0%;"}
20
20
  {% } %}
21
21
  %td
22
22
  {% if (!o.files.error && !i && !o.options.autoUpload) { %}
23
23
  %button.btn.btn-primary.start
24
- %i.icon-upload.icon-white
24
+ %i.glyphicon.glyphicon-upload
25
25
  %span Start
26
26
  {% } %}
27
27
  {% if (!i) { %}
28
28
  %button.btn.btn-warning.cancel
29
- %i.icon-ban-circle.icon-white
29
+ %i.glyphicon.glyphicon-ban-circle
30
30
  %span Cancel
31
31
  {% } %}
32
32
  {% } %}
@@ -10,11 +10,22 @@
10
10
  {% } %}
11
11
  %td
12
12
  %p.name
13
- %a{:href => "{%=o.url%}", :title => "{%=o.name%}", :download => "{%=o.name%}", :"data-gallery" => !"{%= o.thumbnailUrl ? 'true' : '' %}".html_safe.empty? && ''} {%=o.name%}
13
+ {% if (o.url) { %}
14
+ %a{:href => "{%=o.url%}", :title => "{%=o.name%}", :download => "{%=o.name%}", :"data-gallery" => !"{%= o.image ? 'true' : '' %}".html_safe.empty? && ''} {%=o.name%}
15
+ {% } else { %}
16
+ %span {%=o.name%}
17
+ {% } %}
14
18
  %td
15
19
  %span.size {%=formatFileSize(o.size)%}
16
20
  %td
21
+ {% if (o.delete_url) { %}
17
22
  %button.btn.btn-danger.delete{"data-type" => "DELETE", "data-url" => "{%=o.delete_url%}", "data-object_id" => "{%=o.id%}", "data-confirmation" => "Are you sure?", "data-xhr-fields" => !"{% if (o.delete_with_credentials) { %} {'withCredentials': true} {% } %}".blank? && "{% if (o.delete_with_credentials) { %} {'withCredentials': true} {% } %}"}
18
23
  %i.icon-trash.icon-white
19
24
  %span Delete
20
25
  %input.toggle{:name => "delete", :type => "checkbox", :value => "1"}
26
+ {% } else { %}
27
+ %button.btn.btn-warning.cancel
28
+ %i.glyphicon.glyphicon-ban-circle
29
+ %span Cancel
30
+ {% } %}
31
+
@@ -1,4 +1,4 @@
1
- = stylesheet_link_tag '//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css'
1
+ = stylesheet_link_tag '//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css'
2
2
 
3
3
  %div{:style => 'padding: 10px;'}
4
4
  %h2 Upload file(s)
@@ -1,2 +1,8 @@
1
1
  require 's3_cors_fileupload/version'
2
2
  require 's3_cors_fileupload/rails'
3
+
4
+ module S3CorsFileupload
5
+ def self.active_record_protected_attributes?
6
+ @active_record_protected_attributes ||= ActiveRecord::VERSION::STRING.to_f < 4.0 || !!defined?(ProtectedAttributes)
7
+ end
8
+ end
@@ -1,6 +1,6 @@
1
1
  if defined?(::Rails)
2
2
  require 's3_cors_fileupload/rails/config'
3
- require 's3_cors_fileupload/rails/engine' if ::Rails.version >= '3.1'
3
+ require 's3_cors_fileupload/rails/engine' if defined? ::Rails::Engine
4
4
  require 's3_cors_fileupload/rails/policy_helper'
5
5
  require 's3_cors_fileupload/rails/form_helper'
6
6
 
@@ -14,6 +14,9 @@ module S3CorsFileupload
14
14
  # :bucket The name of the bucket on S3 you wish for the files to be uploaded to.
15
15
  # Defaults to `Config.bucket` (read from the yaml config file).
16
16
  #
17
+ # :secure Dictates whether the form action URL will be pointing to a secure URL or not.
18
+ # Defaults to `true`.
19
+ #
17
20
  # Any other key creates standard HTML options for the form tag.
18
21
  def s3_cors_fileupload_form_tag(options = {}, &block)
19
22
  policy_helper = PolicyHelper.new(options)
@@ -28,9 +31,9 @@ module S3CorsFileupload
28
31
  :success_action_status => '201'
29
32
  }
30
33
  # assume that all of the non-documented keys are
31
- _html_options = options.reject { |key, val| [:access_key_id, :acl, :max_file_size, :bucket].include?(key) }
34
+ _html_options = options.reject { |key, val| [:access_key_id, :acl, :max_file_size, :bucket, :secure].include?(key) }
32
35
  # return the form html
33
- construct_form_html(hidden_form_fields, policy_helper.options[:bucket], _html_options, &block)
36
+ construct_form_html(hidden_form_fields, policy_helper.options[:bucket], options[:secure], _html_options, &block)
34
37
  end
35
38
 
36
39
  alias_method :s3_cors_fileupload_form, :s3_cors_fileupload_form_tag
@@ -42,31 +45,31 @@ module S3CorsFileupload
42
45
  end
43
46
 
44
47
  # hidden fields argument should be a hash of key value pairs (values may be blank if desired)
45
- def construct_form_html(hidden_fields, bucket, html_options = {}, &block)
48
+ def construct_form_html(hidden_fields, bucket, secure = true, html_options = {}, &block)
46
49
  # now build the html for the form
47
- form_tag("https://#{bucket}.s3.amazonaws.com", build_form_options(html_options)) do
50
+ form_tag(secure == false ? "http://#{bucket}.s3.amazonaws.com" : "https://#{bucket}.s3.amazonaws.com", build_form_options(html_options)) do
48
51
  hidden_fields.map do |name, value|
49
52
  hidden_field_tag(name, value)
50
53
  end.join.html_safe + "
51
54
  <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload -->
52
55
  <div class='row fileupload-buttonbar'>
53
- <div class='span7'>
56
+ <div class='col-lg-7'>
54
57
  <span class='btn btn-success fileinput-button'>
55
- <i class='icon-plus icon-white'></i>
58
+ <i class='glyphicon glyphicon-plus'></i>
56
59
  <span>Add files...</span>
57
60
  ".html_safe +
58
61
  file_field_tag(:file, :multiple => true) + "
59
62
  </span>
60
63
  <button type='submit' class='btn btn-primary start'>
61
- <i class='icon-upload icon-white'></i>
64
+ <i class='glyphicon glyphicon-upload'></i>
62
65
  <span>Start upload</span>
63
66
  </button>
64
67
  <button type='reset' class='btn btn-warning cancel'>
65
- <i class='icon-ban-circle icon-white'></i>
68
+ <i class='glyphicon glyphicon-ban-circle'></i>
66
69
  <span>Cancel upload</span>
67
70
  </button>
68
71
  <button type='button' class='btn btn-danger delete'>
69
- <i class='icon-trash icon-white'></i>
72
+ <i class='glyphicon glyphicon-trash'></i>
70
73
  <span>Delete</span>
71
74
  </button>
72
75
  <input type='checkbox' class='toggle'></input>
@@ -74,10 +77,10 @@ module S3CorsFileupload
74
77
  <span class='fileupload-loading'></span>
75
78
  </div>
76
79
  <!-- The global progress information -->
77
- <div class='span5 fileupload-progress fade'>
80
+ <div class='col-lg-5 fileupload-progress fade'>
78
81
  <!-- The global progress bar -->
79
- <div class='progress progress-success progress-striped active' role='progressbar' aria-valuemin='0' aria-valuemax='100'>
80
- <div class='bar' style='width: 0%;'></div>
82
+ <div class='progress progress-striped active' role='progressbar' aria-valuemin='0' aria-valuemax='100'>
83
+ <div class='progress-bar progress-bar-success' style='width: 0%;'></div>
81
84
  </div>
82
85
  <!-- The extended global progress information -->
83
86
  <div class='progress-extended'>&nbsp;</div>
@@ -1,5 +1,5 @@
1
1
  module S3CorsFileupload
2
- VERSION = '0.2.1'
3
- JQUERY_FILEUPLOAD_VERSION = '5.32.0'
4
- JQUERY_FILEUPLOAD_UI_VERSION = '8.5.0'
2
+ VERSION = '0.3.0'
3
+ JQUERY_FILEUPLOAD_VERSION = '5.32.6'
4
+ JQUERY_FILEUPLOAD_UI_VERSION = '8.8.5'
5
5
  end
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.version = S3CorsFileupload::VERSION
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Ben Atkins"]
9
- s.email = ["benatkins@fullbridge.com"]
9
+ s.email = ["batkinz@gmail.com"]
10
10
  s.homepage = "http://github.com/fullbridge-batkins/s3_cors_fileupload"
11
11
  s.summary = "File uploads for Rails ~> 3.1 to AWS-S3 via CORS using the jQuery-File-Upload script"
12
12
  s.description = "Provides file uploads for Rails ~> 3.1 to AWS-S3 via CORS using the jQuery-File-Upload javascript"
@@ -23,10 +23,9 @@ Gem::Specification.new do |s|
23
23
  s.extra_rdoc_files = %w(README.md CHANGELOG.md LICENSE.txt)
24
24
  s.rdoc_options = %w(--charset=UTF-8)
25
25
 
26
- s.add_dependency('rails', ['~> 3.1'])
26
+ s.add_dependency('rails', ['>= 3.1', '< 5.0'])
27
27
  s.add_dependency('multi_json', ['~> 1.0'])
28
- s.add_dependency('jquery-rails', ['>= 2.0'])
29
- s.add_dependency('aws-s3', ['~> 0.6']) # :require => 'aws/s3'
28
+ s.add_dependency('aws-s3', ['~> 0.6'])
30
29
 
31
30
  s.add_development_dependency('rake', ['>= 0.8.7'])
32
31
  s.add_development_dependency('bundler', ['>= 0'])
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env rake
2
1
  # Add your own tasks in files placed in lib/tasks ending in .rake,
3
2
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
3
 
@@ -5,11 +5,12 @@
5
5
  // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
6
  //
7
7
  // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
- // the compiled file.
8
+ // compiled file.
9
9
  //
10
- // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
- // GO AFTER THE REQUIRES BELOW.
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
12
  //
13
13
  //= require jquery
14
14
  //= require jquery_ujs
15
+ //= require s3_cors_fileupload
15
16
  //= require_tree .
@@ -0,0 +1,92 @@
1
+ /*
2
+ * s3-cors-file-upload
3
+ * http://github.com/fullbridge-batkins/s3_cors_fileupload
4
+ *
5
+ * Copyright 2013, Ben Atkins
6
+ * http://batkins.net
7
+ *
8
+ * Licensed under the MIT license:
9
+ * http://www.opensource.org/licenses/MIT
10
+ */
11
+
12
+ // This global variable will hold s3 file credentials for files until it's time to submit them
13
+ var s3_upload_hash = {};
14
+
15
+ $(function() {
16
+ // hit the controller for info when the file comes in
17
+ $('#fileupload').bind('fileuploadadd', function (e, data) {
18
+ var content_type = data.files[0].type;
19
+ var file_name = data.files[0].name;
20
+
21
+ $.getJSON('/source_files/generate_key.json', {filename: file_name}, function(data) {
22
+ // Now that we have our data, we add it to the global s3_upload_hash so that it can be
23
+ // accessed (in the fileuploadsubmit callback) prior to being submitted
24
+ s3_upload_hash[file_name] = {
25
+ key: data.key,
26
+ content_type: content_type
27
+ };
28
+ });
29
+ });
30
+
31
+ // this gets triggered right before a file is about to be sent (and have their form action submitted)
32
+ $('#fileupload').bind('fileuploadsubmit', function (e, data) {
33
+ var file_name = data.files[0].name;
34
+ // transfer the data from the upload-template .form hidden fields to the real form's hidden fields
35
+ var form = $('#fileupload');
36
+ form.find('input[name=key]').val(s3_upload_hash[file_name]['key']);
37
+ form.find('input[name=Content-Type]').val(s3_upload_hash[file_name]['content_type']);
38
+ delete s3_upload_hash[file_name];
39
+ });
40
+
41
+ $('#fileupload').bind('fileuploaddone', function (e, data) {
42
+ // the response will be XML, and can be accessed by calling `data.result`
43
+ //
44
+ // Here is an example of what the XML will look like coming back from S3:
45
+ // <PostResponse>
46
+ // <Location>https://bucket-name.s3.amazonaws.com/uploads%2F3ducks.jpg</Location>
47
+ // <Bucket>bucket-name</Bucket>
48
+ // <Key>uploads/3ducks.jpg</Key>
49
+ // <ETag>"c7902ef289687931f34f92b65afda320"</ETag>
50
+ // </PostResponse>
51
+
52
+ $.post('/source_files.json',
53
+ {
54
+ 'source_file[url]': $(data.result).find('Location').text(),
55
+ 'source_file[bucket]': $(data.result).find('Bucket').text(),
56
+ 'source_file[key]': $(data.result).find('Key').text(),
57
+ authenticity_token: $('meta[name=csrf-token]').attr('content')
58
+ },
59
+ function(data) {
60
+ $('#upload_files tbody').append(tmpl('template-uploaded', data));
61
+ },
62
+ 'json'
63
+ );
64
+ });
65
+
66
+ $('#fileupload').bind('fileuploadcompleted', function (e, data) {
67
+ // remove the downloaded templates, since in the above function we put our own custom 'template-uploaded' onto the list instead
68
+ data.context.remove();
69
+ });
70
+
71
+ $('#fileupload').bind('fileuploaddestroyed', function (e, data) {
72
+ if (!data.url) // sometimes this callback seems to get triggered a couple times, and has null data after the first time
73
+ return null;
74
+
75
+ // remove the table row containing the source file information from the page
76
+ $('#source_file_' + data.object_id).remove();
77
+ });
78
+
79
+ });
80
+
81
+ // used for displaying approximate file size on the file listing index.
82
+ // functionality mimics what the jQuery-File-Upload script does.
83
+ function formatFileSize(bytes) {
84
+ if (typeof bytes !== 'number')
85
+ return '';
86
+ else if (bytes >= 1000000000)
87
+ return (bytes / 1000000000).toFixed(2) + ' GB';
88
+ else if (bytes >= 1000000)
89
+ return (bytes / 1000000).toFixed(2) + ' MB';
90
+ else
91
+ return (bytes / 1000).toFixed(2) + ' KB';
92
+ }
@@ -9,5 +9,6 @@
9
9
  * compiled file, but it's generally better to create a new file per style scope.
10
10
  *
11
11
  *= require_self
12
+ *= require jquery.fileupload-ui
12
13
  *= require_tree .
13
14
  */
@@ -1,3 +1,5 @@
1
1
  class ApplicationController < ActionController::Base
2
- protect_from_forgery
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
3
5
  end
@@ -0,0 +1,56 @@
1
+ class S3UploadsController < ApplicationController
2
+ # GET /source_files
3
+ # GET /source_files.json
4
+ def index
5
+ @source_files = SourceFile.all
6
+
7
+ respond_to do |format|
8
+ format.html # index.html.erb
9
+ format.json { render json: @source_files.map(&:to_jq_upload) }
10
+ end
11
+ end
12
+
13
+ # POST /source_files
14
+ # POST /source_files.json
15
+ def create
16
+ # this line allows for compatibility with `ProtectedAttributes` or `StrongParameters`
17
+ parameters = S3CorsFileupload.active_record_protected_attributes? ? params[:source_file] : params.require(:source_file).permit(:url, :bucket, :key)
18
+ @source_file = SourceFile.new(parameters)
19
+ respond_to do |format|
20
+ if @source_file.save
21
+ format.html {
22
+ render :json => @source_file.to_jq_upload,
23
+ :content_type => 'text/html',
24
+ :layout => false
25
+ }
26
+ format.json { render json: @source_file.to_jq_upload, status: :created }
27
+ else
28
+ format.html { render action: "new" }
29
+ format.json { render json: @source_file.errors, status: :unprocessable_entity }
30
+ end
31
+ end
32
+ end
33
+
34
+ # DELETE /source_files/1
35
+ # DELETE /source_files/1.json
36
+ def destroy
37
+ @source_file = SourceFile.find(params[:id])
38
+ @source_file.destroy
39
+
40
+ respond_to do |format|
41
+ format.html { redirect_to source_files_url }
42
+ format.json { head :no_content }
43
+ format.xml { head :no_content }
44
+ end
45
+ end
46
+
47
+ # used for s3_uploader
48
+ def generate_key
49
+ uid = SecureRandom.uuid.gsub(/-/,'')
50
+
51
+ render json: {
52
+ key: "uploads/#{uid}/#{params[:filename]}",
53
+ success_action_redirect: "/"
54
+ }
55
+ end
56
+ end
@@ -0,0 +1,54 @@
1
+ require 'aws/s3'
2
+
3
+ class SourceFile < ActiveRecord::Base
4
+ # This line can be removed for Rails 4 apps that are using Strong Parameters
5
+ attr_accessible :url, :bucket, :key if S3CorsFileupload.active_record_protected_attributes?
6
+
7
+ validates_presence_of :file_name, :file_content_type, :file_size, :key, :bucket
8
+
9
+ before_validation(:on => :create) do
10
+ self.file_name = key.split('/').last if key
11
+ # for some reason, the response from AWS seems to escape the slashes in the keys, this line will unescape the slash
12
+ self.url = url.gsub(/%2F/, '/') if url
13
+ self.file_size ||= s3_object.size rescue nil
14
+ self.file_content_type ||= s3_object.content_type rescue nil
15
+ end
16
+ # make all attributes readonly after creating the record (not sure we need this?)
17
+ after_create { readonly! }
18
+ # cleanup; destroy corresponding file on S3
19
+ after_destroy { s3_object.try(:delete) }
20
+
21
+ def to_jq_upload
22
+ {
23
+ 'id' => id,
24
+ 'name' => file_name,
25
+ 'size' => file_size,
26
+ 'url' => url,
27
+ 'image' => self.is_image?,
28
+ 'delete_url' => Rails.application.routes.url_helpers.source_file_path(self, :format => :json)
29
+ }
30
+ end
31
+
32
+ def is_image?
33
+ !!file_content_type.try(:match, /image/)
34
+ end
35
+
36
+ #---- start S3 related methods -----
37
+ def s3_object
38
+ @s3_object ||= AWS::S3::S3Object.find(key, bucket) if self.class.open_aws && key
39
+ rescue
40
+ nil
41
+ end
42
+
43
+ def self.open_aws
44
+ unless @aws_connected
45
+ AWS::S3::Base.establish_connection!(
46
+ :access_key_id => S3CorsFileupload::Config.access_key_id,
47
+ :secret_access_key => S3CorsFileupload::Config.secret_access_key
48
+ )
49
+ end
50
+ @aws_connected ||= AWS::S3::Base.connected?
51
+ end
52
+ #---- end S3 related methods -----
53
+
54
+ end