refile 0.2.2 → 0.2.3

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 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