refile 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c82ae33f74a7a012f5d04acd5c72ad9675b4e3b7
4
- data.tar.gz: 984abf68f34e0725fb18164c0923eeaa2b992b86
3
+ metadata.gz: 8cbf36645ba19dcbaad5d4b56f88a1aa647515fb
4
+ data.tar.gz: a422fc72ee72b28c0953251d9109902ad7d4f1ab
5
5
  SHA512:
6
- metadata.gz: 7393be87fdddfc7fd09b46bfab369dc9364ef30b1f61ebd03de568bc826101206de81474ee6f03215672bd7794d1ce017deadc403b062cba545132d3177aa565
7
- data.tar.gz: 53ff261be44222e0fe7afac11e30372ed488884695bcca01569f2a1e58e3f30100765cda72349f4cac54b24a6f8fba660ae6bbf7d2699b739cbb253f69194176
6
+ metadata.gz: 4bb6048ad95f7b66f847d46c6228ab82c3eb1a59006e7467627eae34d4243eb2ed6851a189eb3828ad8aa4fdcfc88bb0a9712d76d396ed7b40a20393a80f5097
7
+ data.tar.gz: 1a61ecebcb311bc6b3a7dd6b5d323195f7df557f40741cf70c8ba00dfc7f6f94de28b582e49835aeb98d633ecc59c6d5ded55a305062d6a98d73076ffd3fcba2
data/History.md ADDED
@@ -0,0 +1,9 @@
1
+ # 0.2.3
2
+
3
+ Release date: 2014-12-08
4
+
5
+ - [ADDED] Support for passing format to processors
6
+ - [FIXED] Support IE10
7
+ - [FIXED] Gracefully degrade on IE9, IE8 and IE7
8
+ - [FIXED] Success event is fired at the appropriate time
9
+ - [FIXED] Works with apps which don't define root_url
data/README.md CHANGED
@@ -124,6 +124,11 @@ Refile.cache = Refile::Backend::S3.new(prefix: "cache", **aws)
124
124
  Refile.store = Refile::Backend::S3.new(prefix: "store", **aws)
125
125
  ```
126
126
 
127
+ And add to your Gemfile:
128
+ ```ruby
129
+ gem "aws-sdk"
130
+ ```
131
+
127
132
  Try this in the quick start example above and your files are now uploaded to
128
133
  S3.
129
134
 
@@ -401,7 +406,9 @@ cross site AJAX requests from posting to buckets. Fixing this is easy though.
401
406
  - Open the "Permission" section
402
407
  - Click "Add CORS Configuration"
403
408
 
404
- The default configuration only allows "GET", you'll want to allow "POST" as well.
409
+ The default configuration only allows "GET", you'll want to allow "POST" as
410
+ well. You'll also want to permit the "Content-Type" header.
411
+
405
412
  It could look something like this:
406
413
 
407
414
  ``` xml
@@ -412,6 +419,7 @@ It could look something like this:
412
419
  <AllowedMethod>POST</AllowedMethod>
413
420
  <MaxAgeSeconds>3000</MaxAgeSeconds>
414
421
  <AllowedHeader>Authorization</AllowedHeader>
422
+ <AllowedHeader>Content-Type</AllowedHeader>
415
423
  </CORSRule>
416
424
  </CORSConfiguration>
417
425
  ```
@@ -1,50 +1,61 @@
1
- "use strict";
2
-
3
- document.addEventListener("change", function(e) {
4
- if(e.target.tagName === "INPUT" && e.target.type === "file" && e.target.dataset.direct) {
5
- var input = e.target;
6
- var file = input.files[0];
7
- if(file) {
8
- var url = e.target.dataset.url;
9
- if(e.target.dataset.fields) {
10
- var fields = JSON.parse(e.target.dataset.fields);
11
- }
1
+ (function() {
2
+ "use strict";
12
3
 
13
- var data = new FormData();
4
+ if(!document.addEventListener) { return }; // IE8
14
5
 
15
- if(fields) {
16
- Object.keys(fields).forEach(function(key) {
17
- data.append(key, fields[key]);
18
- });
6
+ document.addEventListener("change", function(e) {
7
+ if(e.target.tagName === "INPUT" && e.target.type === "file" && e.target.getAttribute("data-direct")) {
8
+ var input = e.target;
9
+ if(!input.files) { return; } // IE9, bail out if file API is not supported.
10
+ var file = input.files[0];
11
+
12
+ var dispatchEvent = function(name, detail) {
13
+ var ev = document.createEvent('CustomEvent');
14
+ ev.initCustomEvent(name, true, false, detail);
15
+ input.dispatchEvent(ev);
19
16
  }
20
- data.append(input.dataset.as, file);
21
-
22
- var xhr = new XMLHttpRequest();
23
- xhr.addEventListener("load", function(e) {
24
- input.classList.remove("uploading")
25
- input.dispatchEvent(new CustomEvent("upload:complete", { detail: xhr.responseText, bubbles: true }));
26
- if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
27
- var id = input.dataset.id || JSON.parse(xhr.responseText).id;
28
- input.dispatchEvent(new CustomEvent("upload:success", { detail: xhr.responseText, bubbles: true }));
29
- input.previousSibling.value = id;
30
- input.removeAttribute("name");
31
- } else {
32
- input.dispatchEvent(new CustomEvent("upload:failure", { detail: xhr.responseText, bubbles: true }));
17
+
18
+ if(file) {
19
+ var url = e.target.getAttribute("data-url");
20
+ if(e.target.getAttribute("data-fields")) {
21
+ var fields = JSON.parse(e.target.getAttribute("data-fields"));
33
22
  }
34
- });
35
23
 
36
- xhr.addEventListener("progress", function(e) {
37
- if (e.lengthComputable) {
38
- input.dispatchEvent(new CustomEvent("upload:progress", { detail: e, bubbles: true }));
24
+ var data = new FormData();
25
+
26
+ if(fields) {
27
+ Object.keys(fields).forEach(function(key) {
28
+ data.append(key, fields[key]);
29
+ });
39
30
  }
40
- });
31
+ data.append(input.getAttribute("data-as"), file);
32
+
33
+ var xhr = new XMLHttpRequest();
34
+ xhr.addEventListener("load", function(e) {
35
+ input.classList.remove("uploading")
36
+ dispatchEvent("upload:complete", xhr.responseText);
37
+ if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
38
+ var id = input.getAttribute("data-id") || JSON.parse(xhr.responseText).id;
39
+ input.previousSibling.value = id;
40
+ input.removeAttribute("name");
41
+ dispatchEvent("upload:success", xhr.responseText);
42
+ } else {
43
+ dispatchEvent("upload:failure", xhr.responseText);
44
+ }
45
+ });
41
46
 
42
- xhr.open("POST", url, true);
43
- xhr.send(data);
47
+ xhr.upload.addEventListener("progress", function(e) {
48
+ if (e.lengthComputable) {
49
+ dispatchEvent("upload:progress", e);
50
+ }
51
+ });
44
52
 
45
- input.classList.add("uploading")
46
- input.dispatchEvent(new CustomEvent("upload:start", { bubbles: true }));
47
- }
48
- }
49
- });
53
+ xhr.open("POST", url, true);
54
+ xhr.send(data);
50
55
 
56
+ input.classList.add("uploading")
57
+ dispatchEvent("upload:start");
58
+ }
59
+ }
60
+ });
61
+ })();
@@ -5,9 +5,12 @@ module AttachmentHelper
5
5
  filename ||= name.to_s
6
6
 
7
7
  backend_name = Refile.backends.key(file.backend)
8
- host = Refile.host || root_url
8
+ host = Refile.host || request.base_url
9
9
 
10
- File.join(host, refile_app_path, backend_name, *args.map(&:to_s), file.id, filename.parameterize("_"))
10
+ filename = filename.parameterize("_")
11
+ filename << "." << format.to_s if format
12
+
13
+ File.join(host, refile_app_path, backend_name, *args.map(&:to_s), file.id, filename)
11
14
  end
12
15
 
13
16
  def attachment_image_tag(record, name, *args, fallback: nil, format: nil, **options)
@@ -27,7 +30,7 @@ module AttachmentHelper
27
30
  cache = options[:object].send(:"#{method}_attachment").cache
28
31
 
29
32
  if options[:direct]
30
- host = Refile.host || root_url
33
+ host = Refile.host || request.base_url
31
34
  backend_name = Refile.backends.key(cache)
32
35
 
33
36
  options[:data] ||= {}
data/lib/refile/app.rb CHANGED
@@ -27,50 +27,51 @@ module Refile
27
27
 
28
28
  def call(env)
29
29
  @logger.info { "Refile: #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]}" }
30
- if env["REQUEST_METHOD"] == "GET"
31
- backend_name, *process_args, id, filename = env["PATH_INFO"].sub(/^\//, "").split("/")
32
- backend = Refile.backends[backend_name]
33
-
34
- if backend and id
35
- @logger.debug { "Refile: serving #{id.inspect} from #{backend_name} backend which is of type #{backend.class}" }
36
-
37
- file = backend.get(id)
38
-
39
- unless process_args.empty?
40
- name = process_args.shift
41
- unless Refile.processors[name]
42
- @logger.debug { "Refile: no such processor #{name.inspect}" }
43
- return not_found
44
- end
45
- file = Refile.processors[name].call(file, *process_args)
46
- end
47
30
 
48
- peek = begin
49
- file.read(Refile.read_chunk_size)
50
- rescue => e
51
- log_error(e)
31
+ backend_name, *args = env["PATH_INFO"].sub(/^\//, "").split("/")
32
+ backend = Refile.backends[backend_name]
33
+
34
+ if env["REQUEST_METHOD"] == "GET" and backend and args.length >= 2
35
+ *process_args, id, filename = args
36
+ format = ::File.extname(filename)[1..-1]
37
+
38
+ @logger.debug { "Refile: serving #{id.inspect} from #{backend_name} backend which is of type #{backend.class}" }
39
+
40
+ file = backend.get(id)
41
+
42
+ unless process_args.empty?
43
+ name = process_args.shift
44
+ processor = Refile.processors[name]
45
+ unless processor
46
+ @logger.debug { "Refile: no such processor #{name.inspect}" }
52
47
  return not_found
53
48
  end
49
+ file = if format
50
+ processor.call(file, *process_args, format: format)
51
+ else
52
+ processor.call(file, *process_args)
53
+ end
54
+ end
54
55
 
55
- headers = {}
56
- headers["Access-Control-Allow-Origin"] = @allow_origin if @allow_origin
57
-
58
- [200, headers, Proxy.new(peek, file)]
59
- else
60
- @logger.debug { "Refile: must specify backend and id" }
61
- not_found
56
+ peek = begin
57
+ file.read(Refile.read_chunk_size)
58
+ rescue => e
59
+ log_error(e)
60
+ return not_found
62
61
  end
63
- elsif env["REQUEST_METHOD"] == "POST"
64
- backend_name, *rest = env["PATH_INFO"].sub(/^\//, "").split("/")
65
- backend = Refile.backends[backend_name]
66
62
 
67
- return not_found unless rest.empty?
68
- return not_found unless backend and Refile.direct_upload.include?(backend_name)
63
+ headers = {}
64
+ headers["Access-Control-Allow-Origin"] = @allow_origin if @allow_origin
65
+
66
+ [200, headers, Proxy.new(peek, file)]
67
+ elsif env["REQUEST_METHOD"] == "POST" and backend and args.empty? and Refile.direct_upload.include?(backend_name)
68
+ @logger.debug { "Refile: uploading to #{backend_name} backend which is of type #{backend.class}" }
69
+
70
+ tempfile = Rack::Request.new(env).params.fetch("file").fetch(:tempfile)
71
+ file = backend.upload(tempfile)
69
72
 
70
- file = backend.upload(Rack::Request.new(env).params.fetch("file").fetch(:tempfile))
71
73
  [200, { "Content-Type" => "application/json" }, [{ id: file.id }.to_json]]
72
74
  else
73
- @logger.debug { "Refile: request methods other than GET and POST are not allowed" }
74
75
  not_found
75
76
  end
76
77
  rescue => e
data/lib/refile/rails.rb CHANGED
@@ -20,17 +20,19 @@ module Refile
20
20
  end
21
21
 
22
22
  class Engine < Rails::Engine
23
- initializer "refile", before: :load_environment_config do
23
+ initializer "refile.setup", before: :load_environment_config do
24
24
  Refile.store ||= Refile::Backend::FileSystem.new(Rails.root.join("tmp/uploads/store").to_s)
25
25
  Refile.cache ||= Refile::Backend::FileSystem.new(Rails.root.join("tmp/uploads/cache").to_s)
26
26
 
27
- Refile.app = Refile::App.new(logger: Rails.logger)
28
-
29
27
  ActiveSupport.on_load :active_record do
30
28
  require "refile/attachment/active_record"
31
29
  end
32
30
 
33
31
  ActionView::Helpers::FormBuilder.send(:include, AttachmentFieldHelper)
34
32
  end
33
+
34
+ initializer "refile.app" do
35
+ Refile.app = Refile::App.new(logger: Rails.logger)
36
+ end
35
37
  end
36
38
  end
@@ -1,3 +1,3 @@
1
1
  module Refile
2
- VERSION = "0.2.2"
2
+ VERSION = "0.2.3"
3
3
  end
@@ -1,22 +1,5 @@
1
1
  require "rack/test"
2
2
 
3
- Refile.processor(:reverse) do |file|
4
- StringIO.new(file.read.reverse)
5
- end
6
-
7
- Refile.processor(:upcase, proc { |file| StringIO.new(file.read.upcase) })
8
-
9
- Refile.processor(:concat) do |file, *words|
10
- content = File.read(file.download.path)
11
- tempfile = Tempfile.new("concat")
12
- tempfile.write(content)
13
- words.each do |word|
14
- tempfile.write(word)
15
- end
16
- tempfile.close
17
- File.open(tempfile.path, "r")
18
- end
19
-
20
3
  describe Refile::App do
21
4
  include Rack::Test::Methods
22
5
 
@@ -114,6 +97,15 @@ describe Refile::App do
114
97
  expect(last_response.status).to eq(200)
115
98
  expect(last_response.body).to eq("hellofoobarbaz")
116
99
  end
100
+
101
+ it "applies processor with format" do
102
+ file = Refile.store.upload(StringIO.new("hello"))
103
+
104
+ get "/store/convert_case/#{file.id}/hello.up"
105
+
106
+ expect(last_response.status).to eq(200)
107
+ expect(last_response.body).to eq("HELLO")
108
+ end
117
109
  end
118
110
 
119
111
  describe "POST /:backend" do
@@ -33,4 +33,15 @@ feature "Normal HTTP Post file uploads" do
33
33
  click_link("Document")
34
34
  expect(page.source.chomp).to eq("hello")
35
35
  end
36
+
37
+ scenario "Format conversion" do
38
+ visit "/normal/posts/new"
39
+ fill_in "Title", with: "A cool post"
40
+ attach_file "Document", path("hello.txt")
41
+ click_button "Create"
42
+
43
+ expect(page).to have_selector("h1", text: "A cool post")
44
+ click_link("Convert to Upper")
45
+ expect(page.source.chomp).to eq("HELLO")
46
+ end
36
47
  end
@@ -24,6 +24,32 @@ Refile.backends["limited_cache"] = FakePresignBackend.new(File.expand_path("defa
24
24
 
25
25
  Refile.direct_upload = ["cache", "limited_cache"]
26
26
 
27
+ Refile.processor(:reverse) do |file|
28
+ StringIO.new(file.read.reverse)
29
+ end
30
+
31
+ Refile.processor(:upcase, proc { |file| StringIO.new(file.read.upcase) })
32
+
33
+ Refile.processor(:concat) do |file, *words|
34
+ content = File.read(file.download.path)
35
+ tempfile = Tempfile.new("concat")
36
+ tempfile.write(content)
37
+ words.each do |word|
38
+ tempfile.write(word)
39
+ end
40
+ tempfile.close
41
+ File.open(tempfile.path, "r")
42
+ end
43
+
44
+ Refile.processor(:convert_case) do |file, format:|
45
+ case format
46
+ when "up" then StringIO.new(file.read.upcase)
47
+ when "down" then StringIO.new(file.read.downcase)
48
+ else file
49
+ end
50
+ end
51
+
52
+
27
53
  class Refile::FileDouble
28
54
  def initialize(data)
29
55
  @io = StringIO.new(data)
@@ -39,6 +39,16 @@ require "capybara/rails"
39
39
  require "capybara/rspec"
40
40
  require "refile/spec_helper"
41
41
 
42
+ if ENV["SAUCE_BROWSER"]
43
+ Capybara.register_driver :selenium do |app|
44
+ url = "http://#{ENV["SAUCE_USERNAME"]}:#{ENV["SAUCE_ACCESS_KEY"]}@localhost:4445/wd/hub"
45
+ capabilities = { browserName: ENV["SAUCE_BROWSER"], version: ENV["SAUCE_VERSION"] }
46
+ driver = Capybara::Selenium::Driver.new(app, browser: :remote, url: url, desired_capabilities: capabilities)
47
+ driver.browser.file_detector = lambda { |args| args.first if File.exist?(args.first) }
48
+ driver
49
+ end
50
+ end
51
+
42
52
  Capybara.configure do |config|
43
53
  config.server_port = 56120
44
54
  end
@@ -3,38 +3,40 @@
3
3
 
4
4
  "use strict";
5
5
 
6
- document.addEventListener("DOMContentLoaded", function() {
7
- var form = document.querySelector("form#direct");
8
-
9
- if(form) {
10
- var input = document.querySelector("#post_document");
11
-
12
- form.addEventListener("upload:start", function() {
13
- var p = document.createElement("p");
14
- p.textContent = "Upload started";
15
- form.appendChild(p);
16
- });
17
-
18
- form.addEventListener("upload:complete", function(e) {
19
- var p = document.createElement("p");
20
- p.textContent = "Upload complete " + e.detail;
21
- form.appendChild(p);
22
- });
23
-
24
- form.addEventListener("upload:progress", function(e) {
25
- var p = document.createElement("p");
26
- p.textContent = "Upload progress " + e.detail.loaded + " " + e.detail.total;
27
- form.appendChild(p);
28
- });
29
-
30
- form.addEventListener("upload:failure", function(e) {
31
- var p = document.createElement("p");
32
- p.textContent = "Upload failure " + e.detail
33
- form.appendChild(p);
34
- });
35
- }
36
- });
37
-
38
- $(document).on("upload:success", "form#direct", function(e) {
39
- $("<p></p>").text("Upload success " + e.originalEvent.detail).appendTo(this);
40
- });
6
+ if(document.addEventListener) {
7
+ document.addEventListener("DOMContentLoaded", function() {
8
+ var form = document.querySelector("form#direct");
9
+
10
+ if(form) {
11
+ var input = document.querySelector("#post_document");
12
+
13
+ form.addEventListener("upload:start", function() {
14
+ var p = document.createElement("p");
15
+ p.textContent = "Upload started";
16
+ form.appendChild(p);
17
+ });
18
+
19
+ form.addEventListener("upload:complete", function(e) {
20
+ var p = document.createElement("p");
21
+ p.textContent = "Upload complete " + e.detail;
22
+ form.appendChild(p);
23
+ });
24
+
25
+ form.addEventListener("upload:progress", function(e) {
26
+ var p = document.createElement("p");
27
+ p.textContent = "Upload progress " + e.detail.loaded + " " + e.detail.total;
28
+ form.appendChild(p);
29
+ });
30
+
31
+ form.addEventListener("upload:failure", function(e) {
32
+ var p = document.createElement("p");
33
+ p.textContent = "Upload failure " + e.detail
34
+ form.appendChild(p);
35
+ });
36
+ }
37
+ });
38
+
39
+ $(document).on("upload:success", "form#direct", function(e) {
40
+ $("<p></p>").text("Upload success " + e.originalEvent.detail).appendTo(this);
41
+ });
42
+ }
@@ -7,3 +7,7 @@
7
7
  <% if @post.document %>
8
8
  <%= link_to "Document", attachment_url(@post, :document) %>
9
9
  <% end %>
10
+
11
+ <% if @post.document %>
12
+ <%= link_to "Convert to Upper", attachment_url(@post, :document, :convert_case, format: "up") %>
13
+ <% end %>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-28 00:00:00.000000000 Z
11
+ date: 2014-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -189,6 +189,7 @@ files:
189
189
  - ".rspec"
190
190
  - ".travis.yml"
191
191
  - Gemfile
192
+ - History.md
192
193
  - LICENSE.txt
193
194
  - README.md
194
195
  - Rakefile