browse-everything 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NTM5M2NhYWU1YjhlZGRmNjkwNDdmZWI5MGFkMjQ5MTliY2E0M2E4Mg==
5
- data.tar.gz: !binary |-
6
- NTg2NmE1MWZlMjQzZGUwYzAyZjljNWNmZTJlYjlhODdiMGY4NTIyYw==
2
+ SHA1:
3
+ metadata.gz: 6a4e41392cdc521780aedf3a678593444dd23663
4
+ data.tar.gz: a34d71298ffa7a50258c4b7e9f1129c71bfa7b9c
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NTY1MzhjMGVlOGZlOTNhMDlmMzAzOWYwMGI1NWYyMzlmMmU4N2U1MGU5NDdj
10
- ZjQxMWMyYmM4NWZhN2E4NTQyMmVlZDVhOWI5NmNiYjVkNDU3ODhiNjgyZDFk
11
- MmE2ZWFhMmNjMzRmNjIzZjYyZDdkZjUwNDE2MTA3YWVlMTU4MWU=
12
- data.tar.gz: !binary |-
13
- NjAxMDg3M2JmZmRiZTAwMWE4NTc4YTU0MmI0NmQzNTI5OTQ5YzNlZjZhY2Nk
14
- N2MxOTBiZjAzMzljOGVkYjk5NzRkOTY4Njg0YTMzZTI3YzVjMmFkOTcwYmVh
15
- NjhmMmE1NDRjMThjODE5NjhiOGIwYzVmYmZhOTNhZjM0ZGY2MTE=
6
+ metadata.gz: a92791fc15d5ea12d87ee7d33716cc1b5cf7e14507a7127b99bb2d7faf12747db4d652012cfbc15d16182593302e9a833ea767ee235f985d329c3b1c3e03ff63
7
+ data.tar.gz: 4cd5134d5e4204172e18dc5dff19d057b20f69a595c769f3666fdb8b08ad6cdfc63d893d8d13dc3045ad3f6010828ca8c5a1007713f1022ec2587d7cb1f0f435
data/.travis.yml CHANGED
@@ -2,8 +2,9 @@ language: ruby
2
2
  rvm:
3
3
  - "1.9.3"
4
4
  - "2.0.0"
5
+ - "2.1.0"
5
6
  notifications:
6
7
  irc: "irc.freenode.org#projecthydra"
7
8
  env:
8
9
  global:
9
- - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
10
+ - NOKOGIRI_USE_SYSTEM_LIBRARIES=true
data/Gemfile CHANGED
@@ -4,3 +4,9 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'spring', group: :development
7
+
8
+ file = File.expand_path("Gemfile", ENV['ENGINE_CART_DESTINATION'] || ENV['RAILS_ROOT'] || File.expand_path("../spec/internal", __FILE__))
9
+ if File.exists?(file)
10
+ puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
11
+ instance_eval File.read(file)
12
+ end
data/HISTORY.md CHANGED
@@ -1,3 +1,8 @@
1
+ ### 0.7.0 (2014-12-10)
2
+ - Add BrowseEverything::Retriever
3
+ - Accessibility improvements
4
+ - Bug fixes
5
+
1
6
  ### 0.6.3 (2014-08-06)
2
7
  - Treat FontAwesome version issues independently of Bootstrap version issues
3
8
 
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/browse-everything.png)](http://badge.fury.io/rb/browse-everything)
2
- [![Build Status](https://travis-ci.org/projecthydra/browse-everything.png?branch=master)](https://travis-ci.org/projecthydra/browse-everything)
2
+ [![Build Status](https://travis-ci.org/projecthydra-labs/browse-everything.svg?branch=master)](https://travis-ci.org/projecthydra-labs/browse-everything)
3
3
 
4
4
  # BrowseEverything
5
5
 
@@ -12,6 +12,8 @@ The gem uses [OAuth](http://oauth.net/) to connect to a user's account and
12
12
  generate a list of single use urls that your application can then use to
13
13
  download the files.
14
14
 
15
+ **This gem does not depend on hydra-head**
16
+
15
17
  ## Installation
16
18
 
17
19
  Add this line to your application's Gemfile:
@@ -121,7 +123,7 @@ If you initialized browse-everything via JavaScript, the results data passed to
121
123
  }, {
122
124
  "url": "https://dl.dropbox.com/fake/Getting%20Started.pdf",
123
125
  "expires": "2014-03-31T20:37:36.731Z",
124
- "file_name": "Getting+Started.pdf"
126
+ "file_name": "Getting Started.pdf"
125
127
  }
126
128
  ]
127
129
  ```
@@ -138,11 +140,37 @@ If you initialized browse-everything via data-attributes and set the _target_ op
138
140
  "1"=>{
139
141
  "url"=>"https://dl.dropbox.com/fake/Getting%20Started.pdf",
140
142
  "expires"=>"2014-03-31T20:37:36.731Z",
141
- "file_name"=>"Getting+Started.pdf"
143
+ "file_name"=>"Getting Started.pdf"
142
144
  }
143
145
  }
144
146
  ```
145
147
 
148
+ ### Retrieving Files
149
+
150
+ The `BrowseEverything::Retriever` class has two methods, `#retrieve` and `#download`, that
151
+ can be used to retrieve selected content. `#retrieve` streams the file by yielding it, chunk
152
+ by chunk, to a block, while `#download` saves it to a local file.
153
+
154
+ Given the above response data:
155
+
156
+ ```ruby
157
+ retriever = BrowseEverything::Retriever.new
158
+ download_spec = params['selected_files']['1']
159
+
160
+ # Retrieve the file, yielding each chunk to a block
161
+ retriever.retrieve(download_spec) do |chunk, retrieved, total|
162
+ # do something with the `chunk` of data received, and/or
163
+ # display some progress using `retrieved` and `total` bytes.
164
+ end
165
+
166
+ # Download the file. If `target_file` isn't specified, the
167
+ # retriever will create a tempfile and return the name.
168
+ retriever.download(download_spec, target_file) do |filename, retrieved, total|
169
+ # The block is still useful for showing progress, but the
170
+ # first argument is the filename instead of a chunk of data.
171
+ end
172
+ ```
173
+
146
174
  ### Examples
147
175
 
148
176
  See `spec/support/app/views/file_handler/index.html` for an example use case. You can also run `rake app:generate` to
@@ -156,3 +184,7 @@ create a fully-functioning demo app in `spec/internal` (though you will have to
156
184
  3. Commit your changes (`git commit -am 'Add some feature'`)
157
185
  4. Push to the branch (`git push origin my-new-feature`)
158
186
  5. Create new Pull Request
187
+
188
+ ## Help
189
+
190
+ For help with Questioning Authority, contact <hydra-tech@googlegroups.com>.
data/Rakefile CHANGED
@@ -6,5 +6,6 @@ Dir.glob('tasks/*.rake').each { |r| import r }
6
6
  ENV["RAILS_ROOT"] ||= 'spec/internal'
7
7
 
8
8
  require 'rspec/core/rake_task'
9
+ require 'engine_cart/rake_task'
9
10
 
10
- task :default => [:ci]
11
+ task :default => [:ci]
@@ -3,7 +3,8 @@ $ ->
3
3
 
4
4
  initialize = (obj,options) ->
5
5
  if $('div#browse-everything').length == 0
6
- dialog = $('<div id="browse-everything" class="ev-browser modal fade"></div>').hide().appendTo('body')
6
+ dialog = $('<div tabindex="-1" id="browse-everything" class="ev-browser modal fade" aria-live="polite" role="dialog" aria-labelledby="beModalLabel"></div>').hide().appendTo('body')
7
+
7
8
  dialog.modal
8
9
  backdrop: 'static'
9
10
  show: false
@@ -25,7 +26,7 @@ $ ->
25
26
  toHiddenFields = (data) ->
26
27
  fields = $.param(data)
27
28
  .split('&')
28
- .map (t) -> t.split('=',2)
29
+ .map (t) -> t.replace('+',' ','g').split('=',2)
29
30
  elements = $(fields).map () ->
30
31
  $("<input type='hidden'/>")
31
32
  .attr('name',decodeURIComponent(this[0]))
@@ -45,22 +46,29 @@ $ ->
45
46
  onNodeExpand: ->
46
47
  node = this
47
48
  $('body').css('cursor','wait')
48
- $.ajax
49
- async: false # Must be false, otherwise loadBranch happens after showChildren?
50
- url: $('a.ev-link',node.row).attr('href')
51
- data:
52
- parent: node.row.data('tt-id')
53
- accept: dialog.data('context').opts.accept
54
- context: dialog.data('context').opts.context
55
- .done (html) ->
56
- rows = $('tbody tr',$(html))
57
- table.treetable("loadBranch", node, rows)
58
- sizeColumns(table)
59
- indicateSelected()
60
- .always ->
61
- $('body').css('cursor','default')
49
+ $("html").addClass("wait")
50
+ size = $(node.row).find('td.ev-file-size').text().trim()
51
+ start = 1
52
+ increment = 1
53
+ if (size.indexOf("MB") >-1)
54
+ start = 10
55
+ increment = 5
56
+ if (size.indexOf("KB") >-1)
57
+ start = 50
58
+ increment = 10
59
+ setProgress(start)
60
+ progressIntervalID = setInterval (->
61
+ start = start + increment
62
+ if start > 99
63
+ start = 99
64
+ setProgress(start)
65
+ ), 2000
66
+ setTimeout (->
67
+ loadFiles(node, table, progressIntervalID)
68
+ ), 10
69
+ $("#file-list tr:first").focus()
62
70
  sizeColumns(table)
63
-
71
+
64
72
  sizeColumns = (table) ->
65
73
  full_width = $('.ev-files').width()
66
74
  table.width(full_width)
@@ -71,6 +79,32 @@ $ ->
71
79
  set_size '.ev-kind', 0.3
72
80
  set_size '.ev-date', 0.2
73
81
 
82
+ loadFiles = (node, table, progressIntervalID)->
83
+ $.ajax
84
+ async: true # Must be false, otherwise loadBranch happens after showChildren?
85
+ url: $('a.ev-link',node.row).attr('href')
86
+ data:
87
+ parent: node.row.data('tt-id')
88
+ accept: dialog.data('context').opts.accept
89
+ context: dialog.data('context').opts.context
90
+ .done (html) ->
91
+ setProgress('100')
92
+ clearInterval progressIntervalID
93
+ rows = $('tbody tr',$(html))
94
+ table.treetable("loadBranch", node, rows)
95
+ $(node).show()
96
+ sizeColumns(table)
97
+ indicateSelected()
98
+ .always ->
99
+ clearInterval progressIntervalID
100
+ $('body').css('cursor','default')
101
+ $("html").removeClass("wait")
102
+
103
+ setProgress = (done)->
104
+ $('#loading_progress').css('width',done+'%')
105
+ $('#loading_progress').html(done+'% complete')
106
+ $('#loading_progress').attr('aria-valuenow', done)
107
+
74
108
  refreshFiles = ->
75
109
  $('.ev-providers select').change()
76
110
 
@@ -86,6 +120,7 @@ $ ->
86
120
  setTimeout refreshFiles, 500
87
121
  ctx.callbacks.show.fire()
88
122
  dialog.modal('show')
123
+
89
124
  if ctx
90
125
  ctx.callback_proxy
91
126
  else
@@ -125,6 +160,7 @@ $ ->
125
160
  .always ->
126
161
  $('body').css('cursor','default')
127
162
  $('.ev-browser').modal('hide')
163
+ $('#browse-btn').focus()
128
164
 
129
165
  $(document).on 'click', '.ev-files table tr', (event) ->
130
166
  $('a.ev-link',this).click() unless event.target.nodeName == 'A'
@@ -148,9 +184,13 @@ $ ->
148
184
  .done (data) ->
149
185
  $('.ev-files').html(data)
150
186
  indicateSelected();
187
+ $('#provider_auth').focus();
151
188
  tableSetup($('table#file-list'))
152
189
  .fail (xhr,status,error) ->
153
- $('.ev-files').html(xhr.responseText)
190
+ if (xhr.responseText.indexOf("Refresh token has expired")>-1)
191
+ $('.ev-files').html("Your sessison has expired please clear your cookies.")
192
+ else
193
+ $('.ev-files').html(xhr.responseText)
154
194
  .always ->
155
195
  $('body').css('cursor','default')
156
196
 
@@ -1,3 +1,3 @@
1
1
  <h2><%=t('browse_everything.auth_prompt.head', provider: provider.name)%></h2>
2
2
  <p><%=t('browse_everything.auth_prompt.text', provider: provider.name)%></p>
3
- <p><%= link_to t('browse_everything.auth_prompt.button_text', provider: provider.name), auth_link, class:"btn btn-primary ev-auth", target:'blank' %></p>
3
+ <p><%= link_to t('browse_everything.auth_prompt.button_text', provider: provider.name), auth_link, class:"btn btn-primary ev-auth", target:'blank', id:'provider_auth' %></p>
@@ -1,17 +1,19 @@
1
1
  <% unless file.relative_parent_path? %>
2
- <tr data-ev-location="<%= file.location %>" data-tt-id="<%=path%>" data-tt-parent-id="<%=parent%>" data-tt-branch="<%=file.container? ? 'true' : 'false'%>">
3
- <td class="<%=file.container? ? 'ev-container' : 'ev-file'%> ev-file-name">
4
- <span class="<%=file.container? ? 'folder' : 'file'%>">
5
- <%= link_to(file.name, browse_everything_engine.contents_path(provider_name,file.id), {:class=>'ev-link'}) %>
6
- </span>
2
+ <tr role="row" tabindex="-1" data-ev-location="<%= file.location %>" data-tt-id="<%=path%>" data-tt-parent-id="<%=parent%>" data-tt-branch="<%=file.container? ? 'true' : 'false'%>">
3
+ <td role="gridcell" class="<%=file.container? ? 'ev-container' : 'ev-file'%> ev-file-name">
4
+ <%= link_to browse_everything_engine.contents_path(provider_name,file.id), {:class=>'ev-link'} do %>
5
+ <span class="<%=file.container? ? 'folder' : 'file'%>" aria-hidden="true"/>
6
+ <%= file.name %>
7
+ <span class="sr-only"><%= file.container? ? ', folder' : ', file' %> </span>
8
+ <% end %>
7
9
  </td>
8
- <td class="ev-file-size">
10
+ <td role="gridcell" class="ev-file-size">
9
11
  <%= number_to_human_size(file.size).sub(/Bytes/,'bytes') %>
10
12
  </td>
11
- <td class="ev-file-kind">
13
+ <td role="gridcell" class="ev-file-kind">
12
14
  <%= file.type %>
13
15
  </td>
14
- <td class="ev-file-date">
16
+ <td role="gridcell" class="ev-file-date">
15
17
  <%= file.mtime.strftime('%F %R') %>
16
18
  </td>
17
19
  </tr>
@@ -1,11 +1,16 @@
1
1
  <% if provider.present? %>
2
- <table id="file-list">
2
+ <div class="progress" id="loading_progress" aria-live="polite">
3
+ <div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 100%;">
4
+ 100% Complete
5
+ </div>
6
+ </div>
7
+ <table id="file-list" role="grid" tabindex="-1" title="Choose files to upload from the table below" aria-live="polite">
3
8
  <thead>
4
- <tr>
5
- <th>Name</th>
6
- <th>Size</th>
7
- <th>Kind</th>
8
- <th>Modified</th>
9
+ <tr role="row" tabindex="-1">
10
+ <th role="columnheader">Name</th>
11
+ <th role="columnheader">Size</th>
12
+ <th role="columnheader">Kind</th>
13
+ <th role="columnheader">Modified</th>
9
14
  </tr>
10
15
  </thead>
11
16
  <% provider.contents(browse_path).each_with_index do |file,index| %>
@@ -1,11 +1,12 @@
1
- <% if bootstrap_three? %><div class="modal-content"><% end %>
1
+ <% if bootstrap_three? %><div class="modal-dialog"><div class="modal-content"><% end %>
2
2
  <div class="modal-header">
3
+ <h4 class="sr-only" id="beModalLabel">Select a provider in the list to browse your files.</h4>
3
4
  <div class="ev-providers">
4
5
  <%= render :partial => 'providers' %>
5
6
  </div>
6
7
  </div>
7
- <div class="modal-body ev-body">
8
- <div class="ev-browser row<%=bs2('-fluid')%>">
8
+ <div class="modal-body ev-body" tabindex="-1">
9
+ <div class="ev-browser row<%=bs2('-fluid')%>" aria-live="polite">
9
10
  <div class="<%=fa3or4('fa3','fa4')%> <%=bs2or3('bs2 span','bs3 col-xs-')%>12 ev-files list">
10
11
  <%= render :partial => 'files' %>
11
12
  </div>
@@ -19,4 +20,4 @@
19
20
  <button class="ev-submit btn btn-primary" data-loading-text="Loading..."><%= t('browse_everything.modal_form.submit')%></button>
20
21
  <% end %>
21
22
  </div>
22
- <% if bootstrap_three? %></div><% end %>
23
+ <% if bootstrap_three? %></div></div><% end %>
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "bootstrap-sass"
28
28
  spec.add_dependency "font-awesome-rails"
29
29
  spec.add_dependency "google-api-client"
30
+ spec.add_dependency "httparty"
30
31
  spec.add_development_dependency "rspec", "~> 3.0"
31
32
  spec.add_development_dependency "rspec-rails"
32
33
  spec.add_development_dependency "rspec-its"
@@ -38,5 +39,6 @@ Gem::Specification.new do |spec|
38
39
  spec.add_development_dependency "vcr"
39
40
  spec.add_development_dependency "sqlite3"
40
41
  spec.add_development_dependency "factory_girl_rails"
42
+ spec.add_development_dependency "engine_cart"
41
43
 
42
44
  end
@@ -1,6 +1,7 @@
1
1
  require "rails"
2
2
  require "browse_everything/version"
3
3
  require "browse_everything/engine"
4
+ require "browse_everything/retriever"
4
5
 
5
6
  module BrowseEverything
6
7
  class InitializationError < RuntimeError; end
@@ -43,7 +43,7 @@ module BrowseEverything
43
43
  file = box_client.file(path)
44
44
  download_url = file.download_url
45
45
  auth_header = {'Authorization' => "Bearer #{@token}"}
46
- extras = { auth_header: auth_header, expires: 1.hour.from_now, file_name:file.name }
46
+ extras = { auth_header: auth_header, expires: 1.hour.from_now, file_name: file.name, file_size: file.size.to_i }
47
47
  [download_url,extras]
48
48
  end
49
49
 
@@ -120,4 +120,4 @@ module BrowseEverything
120
120
  end
121
121
 
122
122
  end
123
- end
123
+ end
@@ -38,7 +38,7 @@ module BrowseEverything
38
38
  end
39
39
 
40
40
  def link_for(path)
41
- [client.media(path)['url'], { expires: 4.hours.from_now, file_name: File.basename(path) }]
41
+ [client.media(path)['url'], { expires: 4.hours.from_now, file_name: File.basename(path), file_size: client.metadata(path)['bytes'].to_i }]
42
42
  end
43
43
 
44
44
  def details(path)
@@ -50,7 +50,9 @@ module BrowseEverything
50
50
  end
51
51
 
52
52
  def link_for(path)
53
- ["file://#{File.expand_path(path)}", { file_name: File.basename(path) }]
53
+ full_path = File.expand_path(path)
54
+ file_size = File.size(full_path).to_i rescue 0
55
+ ["file://#{full_path}", { file_name: File.basename(path), file_size: file_size }]
54
56
  end
55
57
 
56
58
  def authorized?
@@ -59,4 +61,4 @@ module BrowseEverything
59
61
  end
60
62
 
61
63
  end
62
- end
64
+ end
@@ -61,7 +61,12 @@ module BrowseEverything
61
61
  api_result = oauth_client.execute(api_method: api_method, parameters: {fileId: id})
62
62
  download_url = JSON.parse(api_result.response.body)["downloadUrl"]
63
63
  auth_header = {'Authorization' => "Bearer #{oauth_client.authorization.access_token.to_s}"}
64
- extras = { auth_header: auth_header, expires: 1.hour.from_now, file_name:api_result.data.title }
64
+ extras = {
65
+ auth_header: auth_header,
66
+ expires: 1.hour.from_now,
67
+ file_name: api_result.data.title,
68
+ file_size: api_result.data.fileSize.to_i
69
+ }
65
70
  [download_url, extras]
66
71
  end
67
72
 
@@ -123,4 +128,4 @@ module BrowseEverything
123
128
  end
124
129
 
125
130
  end
126
- end
131
+ end
@@ -47,7 +47,7 @@ module BrowseEverything
47
47
 
48
48
  def link_for(path)
49
49
  response = Skydrive::Client.new(rehydrate_token).get("/#{real_id(path)}/")
50
- [response.download_link, {expires: 1.hour.from_now, file_name: File.basename(path)}]
50
+ [response.download_link, {expires: 1.hour.from_now, file_name: File.basename(path), file_size: response.size.to_i}]
51
51
  end
52
52
 
53
53
 
@@ -0,0 +1,60 @@
1
+ require 'httparty'
2
+ require 'tempfile'
3
+
4
+ module BrowseEverything
5
+ class Retriever
6
+ attr_accessor :chunk_size
7
+
8
+ def initialize
9
+ @chunk_size = 16384
10
+ end
11
+
12
+ def download(spec, target=nil)
13
+ if target.nil?
14
+ ext = File.extname(spec['file_name'])
15
+ base = File.basename(spec['file_name'],ext)
16
+ target = Dir::Tmpname.create([base,ext]) {}
17
+ end
18
+
19
+ File.open(target, 'wb') do |output|
20
+ self.retrieve(spec) do |chunk, retrieved, total|
21
+ output.write(chunk)
22
+ yield(target, retrieved, total) if block_given?
23
+ end
24
+ end
25
+ return target
26
+ end
27
+
28
+ def retrieve(spec, &block)
29
+ if spec.has_key?('expires') and Time.parse(spec['expires']) < Time.now
30
+ raise ArugumentError, "Download spec expired at #{spec['expires']}"
31
+ end
32
+
33
+ url = URI.parse(spec['url'])
34
+ retrieved = 0
35
+ case url.scheme
36
+ when 'file'
37
+ File.open(url.path,'rb') do |f|
38
+ while not f.eof?
39
+ chunk = f.read(chunk_size)
40
+ retrieved += chunk.length
41
+ yield(chunk, retrieved, spec['file_size'].to_i)
42
+ end
43
+ end
44
+ when /https?/
45
+ headers = spec['auth_header'] || {}
46
+ headers.each_pair do |k,v|
47
+ headers[k] = v.gsub(/\+/,' ')
48
+ end
49
+
50
+ HTTParty.get(url.to_s, headers: headers) do |chunk|
51
+ retrieved += chunk.length
52
+ yield(chunk, retrieved, spec['file_size'].to_i)
53
+ end
54
+ else
55
+ raise URI::BadURIError, "Unknown URI scheme: #{uri.scheme}"
56
+ end
57
+ end
58
+
59
+ end
60
+ end