browse-everything 0.16.1 → 1.0.0.rc1

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 (32) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +3 -0
  3. data/CODE_OF_CONDUCT.md +36 -0
  4. data/CONTRIBUTING.md +21 -19
  5. data/Gemfile +1 -0
  6. data/README.md +29 -9
  7. data/SUPPORT.md +5 -0
  8. data/app/controllers/browse_everything_controller.rb +7 -3
  9. data/app/views/browse_everything/_files.html.erb +14 -6
  10. data/app/views/browse_everything/index.html.erb +7 -1
  11. data/browse-everything.gemspec +5 -5
  12. data/lib/browse_everything/driver/base.rb +1 -1
  13. data/lib/browse_everything/driver/box.rb +4 -14
  14. data/lib/browse_everything/driver/dropbox.rb +34 -11
  15. data/lib/browse_everything/driver/google_drive.rb +2 -2
  16. data/lib/browse_everything/driver/s3.rb +8 -14
  17. data/lib/browse_everything/retriever.rb +4 -5
  18. data/lib/browse_everything/version.rb +1 -1
  19. data/lib/generators/browse_everything/templates/browse_everything_providers.yml.example +2 -2
  20. data/spec/controllers/browse_everything_controller_spec.rb +8 -1
  21. data/spec/lib/browse_everything/driver/box_spec.rb +114 -34
  22. data/spec/lib/browse_everything/driver/dropbox_spec.rb +53 -5
  23. data/spec/lib/browse_everything/driver/google_drive_spec.rb +41 -4
  24. data/spec/lib/browse_everything/driver/s3_spec.rb +27 -18
  25. data/spec/lib/browse_everything/retriever_spec.rb +65 -2
  26. data/spec/spec_helper.rb +4 -9
  27. data/spec/support/capybara.rb +14 -10
  28. metadata +31 -37
  29. data/spec/fixtures/vcr_cassettes/box.yml +0 -498
  30. data/spec/fixtures/vcr_cassettes/dropbox.yml +0 -282
  31. data/spec/fixtures/vcr_cassettes/google_drive.yml +0 -331
  32. data/spec/fixtures/vcr_cassettes/retriever.yml +0 -170
@@ -120,7 +120,7 @@ module BrowseEverything
120
120
 
121
121
  # Provides a URL for authorizing against Google Drive
122
122
  # @return [String] the URL
123
- def auth_link
123
+ def auth_link(*_args)
124
124
  Addressable::URI.parse(authorizer.get_authorization_url)
125
125
  end
126
126
 
@@ -175,7 +175,7 @@ module BrowseEverything
175
175
  # @param params [Hash] HTTP response passed to the OAuth callback
176
176
  # @param _data [Object,nil] an unused parameter
177
177
  # @return [String] a new access token
178
- def connect(params, _data)
178
+ def connect(params, _data, _url_options)
179
179
  @code = params[:code]
180
180
  authorize!
181
181
  end
@@ -8,7 +8,7 @@ module BrowseEverything
8
8
  class S3 < Base
9
9
  DEFAULTS = { response_type: :signed_url, expires_in: 14400 }.freeze
10
10
  RESPONSE_TYPES = %i[signed_url public_url s3_uri].freeze
11
- CONFIG_KEYS = %i[bucket].freeze
11
+ CONFIG_KEYS = %i[bucket region].freeze
12
12
 
13
13
  class << self
14
14
  attr_accessor :authentication_klass
@@ -21,9 +21,10 @@ module BrowseEverything
21
21
  attr_reader :entries
22
22
 
23
23
  def initialize(config, *args)
24
- if config.key?(:signed_url) && config.delete(:signed_url) == false
25
- warn '[DEPRECATION] Amazon S3 driver: `:signed_url` is deprecated. Please use `:response_type` instead.'
26
- config[:response_type] = :public_url
24
+ if config.key?(:signed_url)
25
+ warn '[DEPRECATION] Amazon S3 driver: `:signed_url` is deprecated. Please use `response_type :signed_url` instead.'
26
+ response_type = config.delete(:signed_url) ? :signed_url : :public_url
27
+ config[:response_type] = response_type
27
28
  end
28
29
  merged_config = DEFAULTS.merge(config)
29
30
  self.class.authentication_klass ||= self.class.default_authentication_klass
@@ -45,7 +46,8 @@ module BrowseEverything
45
46
  # @return [Array<BrowseEverything::FileEntry>]
46
47
  def contents(path = '')
47
48
  path = File.join(path, '') unless path.empty?
48
- init_entries(path)
49
+ @entries = []
50
+
49
51
  generate_listing(path)
50
52
  @sorter.call(@entries)
51
53
  end
@@ -111,15 +113,6 @@ module BrowseEverything
111
113
  @client ||= authenticate
112
114
  end
113
115
 
114
- def init_entries(path)
115
- @entries = if path.empty?
116
- []
117
- else
118
- [BrowseEverything::FileEntry.new(Pathname(path).join('..').to_s, '', '..',
119
- 0, Time.current, true)]
120
- end
121
- end
122
-
123
116
  def entry_for(name, size, date, dir)
124
117
  BrowseEverything::FileEntry.new(name, [key, name].join(':'), File.basename(name), size, date, dir)
125
118
  end
@@ -138,6 +131,7 @@ module BrowseEverything
138
131
  end
139
132
 
140
133
  def generate_listing(path)
134
+ client
141
135
  listing = client.list_objects(bucket: config[:bucket], delimiter: '/', prefix: full_path(path))
142
136
  add_directories(listing)
143
137
  add_files(listing, path)
@@ -70,7 +70,7 @@ module BrowseEverything
70
70
  end
71
71
 
72
72
  download_options = extract_download_options(options)
73
- url = download_options.fetch(:url)
73
+ url = download_options[:url]
74
74
 
75
75
  case url.scheme
76
76
  when 'file'
@@ -91,8 +91,7 @@ module BrowseEverything
91
91
  url = options.fetch('url')
92
92
 
93
93
  # This avoids the potential for a KeyError
94
- headers = options.fetch('auth_header', {}) || {}
95
- headers.each_pair { |k, v| headers[k] = v.tr('+', ' ') }
94
+ headers = options.fetch('headers', {}) || {}
96
95
 
97
96
  file_size_value = options.fetch('file_size', 0)
98
97
  file_size = file_size_value.to_i
@@ -131,9 +130,9 @@ module BrowseEverything
131
130
  url = options.fetch(:url)
132
131
  retrieved = 0
133
132
 
134
- request = Typhoeus::Request.new(url.to_s, headers: headers)
133
+ request = Typhoeus::Request.new(url.to_s, method: :get, headers: headers)
135
134
  request.on_headers do |response|
136
- raise DownloadError.new("#{self.class}: Failed to download #{url}", response) unless response.code == 200
135
+ raise DownloadError.new("#{self.class}: Failed to download #{url}: Status Code: #{response.code}", response) unless response.code == 200
137
136
  end
138
137
  request.on_body do |chunk|
139
138
  retrieved += chunk.bytesize
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BrowseEverything
4
- VERSION = '0.16.1'
4
+ VERSION = '1.0.0.rc1'
5
5
  end
@@ -3,8 +3,8 @@
3
3
  # The file_system provider can be a path to any directory on the server where your application is running.
4
4
  #
5
5
  # dropbox:
6
- # app_key: YOUR_DROPBOX_APP_KEY
7
- # app_secret: YOUR_DROPBOX_APP_SECRET
6
+ # client_id: YOUR_DROPBOX_APP_KEY
7
+ # client_secret: YOUR_DROPBOX_APP_SECRET
8
8
  # box:
9
9
  # client_id: YOUR_BOX_CLIENT_ID
10
10
  # client_secret: YOUR_BOX_CLIENT_SECRET
@@ -15,6 +15,13 @@ RSpec.describe BrowseEverythingController, type: :controller do
15
15
 
16
16
  describe '#auth' do
17
17
  let(:provider_session) { instance_double(BrowseEverythingSession::ProviderSession) }
18
+ let(:connector_response_url_options) do
19
+ {
20
+ protocol: 'http://',
21
+ host: 'test.host',
22
+ port: 80
23
+ }
24
+ end
18
25
 
19
26
  before do
20
27
  allow(controller).to receive(:params).and_return('code' => 'test-code')
@@ -24,7 +31,7 @@ RSpec.describe BrowseEverythingController, type: :controller do
24
31
  end
25
32
 
26
33
  it 'retrieves the authorization code from the parameters' do
27
- expect(provider).to have_received(:connect).with({ 'code' => 'test-code' }, nil)
34
+ expect(provider).to have_received(:connect).with({ 'code' => 'test-code' }, nil, connector_response_url_options)
28
35
  end
29
36
  end
30
37
 
@@ -2,7 +2,9 @@
2
2
 
3
3
  include BrowserConfigHelper
4
4
 
5
- describe BrowseEverything::Driver::Box, vcr: { cassette_name: 'box', record: :none } do
5
+ describe BrowseEverything::Driver::Box do
6
+ subject { provider }
7
+
6
8
  let(:browser) { BrowseEverything::Browser.new(url_options) }
7
9
  let(:provider) { browser.providers['box'] }
8
10
  let(:auth_params) do
@@ -11,31 +13,27 @@ describe BrowseEverything::Driver::Box, vcr: { cassette_name: 'box', record: :no
11
13
  'state' => 'box'
12
14
  }
13
15
  end
14
-
15
- # To re-record the VCR responses, you will need to substitute the 'token' and 'refresh_token' values with the
16
- # actual tokens returned from Box.
17
- #
18
- # The easiest way to do this is output @token to the Rails log from the box_client method:
19
- #
20
- # def box_client
21
- # Rails.logger.info(@token)
22
- # [...]
23
- #
24
- # Make sure you have the internal_test_app built and have copied your client id and secret to the yaml config file.
25
- # With the test app running, you can authenticate to your Box account to browse files, and should see the
26
- # tokens listed in the Rails log. Once you have copied the new tokens, the spec test will run and use your tokens
27
- # to authenticate to Box. To record the new responses replace `record: :none` with `record: :all`.
28
16
  let(:token) do
29
17
  {
30
18
  'token' => 'TOKEN',
31
19
  'refresh_token' => 'REFRESH_TOKEN'
32
20
  }
33
21
  end
34
-
35
- subject { provider }
22
+ let(:oauth_response_body) { '{"access_token":"TOKEN","expires_in":3762,"restricted_to":[],"refresh_token":"REFRESH_TOKEN","token_type":"bearer"}' }
36
23
 
37
24
  before do
38
25
  stub_configuration
26
+
27
+ stub_request(
28
+ :post,
29
+ 'https://www.box.com/api/oauth2/token'
30
+ ).to_return(
31
+ body: oauth_response_body,
32
+ status: 200,
33
+ headers: {
34
+ 'Content-Type' => 'application/json'
35
+ }
36
+ )
39
37
  end
40
38
 
41
39
  after do
@@ -48,7 +46,7 @@ describe BrowseEverything::Driver::Box, vcr: { cassette_name: 'box', record: :no
48
46
 
49
47
  describe '#validate_config' do
50
48
  it 'raises and error with an incomplete configuration' do
51
- expect { BrowseEverything::Driver::Box.new({}) }.to raise_error(BrowseEverything::InitializationError)
49
+ expect { described_class.new({}) }.to raise_error(BrowseEverything::InitializationError)
52
50
  end
53
51
  end
54
52
 
@@ -92,14 +90,42 @@ describe BrowseEverything::Driver::Box, vcr: { cassette_name: 'box', record: :no
92
90
  end
93
91
 
94
92
  it 'registers new tokens' do
95
- provider.connect(auth_params, 'data')
93
+ provider.connect(auth_params, 'data', nil)
96
94
  expect(provider).to have_received(:register_access_token).with(kind_of(OAuth2::AccessToken))
97
95
  end
98
96
  end
99
97
 
100
98
  describe '#contents' do
101
- before { provider.token = token }
99
+ let(:folders_response_body) do
100
+ '{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files","created_at":null,"modified_at":null,"description":"","size":28747877,"path_collection":{"total_count":0,"entries":[]},"created_by":{"type":"user","id":"","name":"","login":""},"modified_by":{"type":"user","id":"225383863","name":"ADAM GARNER WEAD","login":"agw13@psu.edu"},"trashed_at":null,"purged_at":null,"content_created_at":null,"content_modified_at":null,"owned_by":{"type":"user","id":"225383863","name":"ADAM GARNER WEAD","login":"agw13@psu.edu"},"shared_link":null,"folder_upload_email":null,"parent":null,"item_status":"active","item_collection":{"total_count":13,"entries":[{"type":"folder","id":"20375782799","sequence_id":"0","etag":"0","name":"A very looooooooooooong box folder, why so loooooooong Lets make it even longer to show how far it gets sent to the side"},{"type":"folder","id":"2571160559","sequence_id":"0","etag":"0","name":"Apps Team - Shared"},{"type":"folder","id":"20194542723","sequence_id":"0","etag":"0","name":"DSRD - W Pattee 3"},{"type":"folder","id":"20284062015","sequence_id":"0","etag":"0","name":"My Box Notes"},{"type":"folder","id":"11305958926","sequence_id":"0","etag":"0","name":"PCDM-Sufia"},{"type":"folder","id":"4227519189","sequence_id":"0","etag":"0","name":"refactor"},{"type":"folder","id":"2459961273","sequence_id":"0","etag":"0","name":"SaS - Development Team"},{"type":"folder","id":"3399219062","sequence_id":"0","etag":"0","name":"Scholarsphere - Migration"},{"type":"folder","id":"1168461187","sequence_id":"0","etag":"0","name":"test"},{"type":"folder","id":"3055812547","sequence_id":"0","etag":"0","name":"UX Artifacts"},{"type":"file","id":"25581309763","file_version":{"type":"file_version","id":"23869158869","sha1":"4604bbe44fdcdd4afef3c666cf582e3773960954"},"sequence_id":"1","etag":"1","sha1":"4604bbe44fdcdd4afef3c666cf582e3773960954","name":"failed.tar.gz"},{"type":"file","id":"25588823531","file_version":{"type":"file_version","id":"23877641673","sha1":"abd18ce0a685a27b464fb05f27af5a84f9ec9be7"},"sequence_id":"1","etag":"1","sha1":"abd18ce0a685a27b464fb05f27af5a84f9ec9be7","name":"scholarsphere_5712md360.xml"},{"type":"file","id":"113711622968","file_version":{"type":"file_version","id":"122136107320","sha1":"da39a3ee5e6b4b0d3255bfef95601890afd80709"},"sequence_id":"0","etag":"0","sha1":"da39a3ee5e6b4b0d3255bfef95601890afd80709","name":"test.txt"}],"offset":0,"limit":100,"order":[{"by":"type","direction":"ASC"},{"by":"name","direction":"ASC"}]}}'
101
+ end
102
+ let(:folders_items_response_body) do
103
+ '{"total_count":13,"entries":[{"type":"folder","id":"20375782799","etag":"0","name":"A very looooooooooooong box folder, why so loooooooong Lets make it even longer to show how far it gets sent to the side","size":0,"created_at":"2017-03-01T04:15:15-08:00"},{"type":"folder","id":"2571160559","etag":"0","name":"Apps Team - Shared","size":1249,"created_at":"2014-10-15T13:00:29-07:00"},{"type":"folder","id":"20194542723","etag":"0","name":"DSRD - W Pattee 3","size":2949416,"created_at":"2017-02-27T08:17:21-08:00"},{"type":"folder","id":"20284062015","etag":"0","name":"My Box Notes","size":0,"created_at":"2017-02-28T08:52:26-08:00"},{"type":"folder","id":"11305958926","etag":"0","name":"PCDM-Sufia","size":650658,"created_at":"2016-09-14T09:14:25-07:00"},{"type":"folder","id":"4227519189","etag":"0","name":"refactor","size":8766,"created_at":"2015-08-14T07:53:56-07:00"},{"type":"folder","id":"2459961273","etag":"0","name":"SaS - Development Team","size":152720753,"created_at":"2014-09-17T13:39:31-07:00"},{"type":"folder","id":"3399219062","etag":"0","name":"Scholarsphere - Migration","size":270984,"created_at":"2015-04-07T13:17:51-07:00"},{"type":"folder","id":"1168461187","etag":"0","name":"test","size":20625445557,"created_at":"2013-09-19T12:57:59-07:00"},{"type":"folder","id":"3055812547","etag":"0","name":"UX Artifacts","size":3801994,"created_at":"2015-02-04T08:21:16-08:00"},{"type":"file","id":"25581309763","etag":"1","name":"failed.tar.gz","size":28650839,"created_at":"2015-01-29T05:18:43-08:00"},{"type":"file","id":"25588823531","etag":"1","name":"scholarsphere_5712md360.xml","size":97038,"created_at":"2015-01-29T08:38:44-08:00"},{"type":"file","id":"113711622968","etag":"0","name":"test.txt","size":0,"created_at":"2016-12-20T07:50:30-08:00"}],"offset":0,"limit":1000,"order":[{"by":"type","direction":"ASC"},{"by":"name","direction":"ASC"}]}'
104
+ end
105
+ before do
106
+ provider.token = token
107
+
108
+ stub_request(
109
+ :get, "https://api.box.com/2.0/folders/0"
110
+ ).to_return(
111
+ body: folders_response_body,
112
+ status: 200,
113
+ headers: {
114
+ 'Content-Type' => 'application/json'
115
+ }
116
+ )
117
+ stub_request(
118
+ :get, "https://api.box.com/2.0/folders/0/items?fields=name,size,created_at&limit=99999&offset=0"
119
+ ).to_return(
120
+ body: folders_items_response_body,
121
+ status: 200,
122
+ headers: {
123
+ 'Content-Type' => 'application/json'
124
+ }
125
+ )
126
+ end
102
127
 
128
+ # HERE
103
129
  context 'with files and folders in the root directory' do
104
130
  let(:root_directory) { provider.contents('') }
105
131
  let(:long_file) { root_directory[0] }
@@ -136,18 +162,36 @@ describe BrowseEverything::Driver::Box, vcr: { cassette_name: 'box', record: :no
136
162
  end
137
163
 
138
164
  context 'with files and folders in the SaS - Development Team directory' do
139
- let(:sas_directory) { provider.contents('2459961273') }
140
- let(:parent_directory) { sas_directory[0] }
141
- let(:apps_dir) { sas_directory[1] }
142
- let(:equipment) { sas_directory[12] }
143
-
144
- describe 'the first item' do
145
- subject { parent_directory }
165
+ let(:folder_id) { '2459961273' }
166
+ let(:sas_directory) { provider.contents(folder_id) }
167
+ let(:apps_dir) { sas_directory[0] }
168
+ let(:equipment) { sas_directory[11] }
169
+ let(:folders_response_body) do
170
+ '{"type":"folder","id":"2459961273","sequence_id":"0","etag":"0","name":"SaS - Development Team","created_at":"2014-09-17T13:39:31-07:00","modified_at":"2017-03-17T08:41:40-07:00","description":"","size":152720753,"path_collection":{"total_count":1,"entries":[{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files"}]},"created_by":{"type":"user","id":"191882215","name":"Daniel Coughlin","login":"dmc186@psu.edu"},"modified_by":{"type":"user","id":"190902775","name":"CAROLYN A COLE","login":"cam156@psu.edu"},"trashed_at":null,"purged_at":null,"content_created_at":"2014-09-17T13:39:31-07:00","content_modified_at":"2017-03-17T08:41:40-07:00","owned_by":{"type":"user","id":"191882215","name":"Daniel Coughlin","login":"dmc186@psu.edu"},"shared_link":{"url":"https:\/\/psu.box.com\/s\/8hb3e06nthwld39ehlg5","download_url":null,"vanity_url":null,"effective_access":"collaborators","is_password_enabled":false,"unshared_at":null,"download_count":0,"preview_count":0,"access":"collaborators","permissions":{"can_download":true,"can_preview":true}},"folder_upload_email":null,"parent":null,"item_status":"active","item_collection":{"total_count":17,"entries":[{"type":"folder","id":"2459974427","sequence_id":"0","etag":"0","name":"Apps&Int"},{"type":"folder","id":"11217040834","sequence_id":"0","etag":"0","name":"Credentials"},{"type":"folder","id":"5662231069","sequence_id":"0","etag":"0","name":"DevOps Presentation"},{"type":"folder","id":"8648394509","sequence_id":"0","etag":"0","name":"old"},{"type":"folder","id":"12445061821","sequence_id":"0","etag":"0","name":"Ops Plan"},{"type":"file","id":"136917954839","file_version":{"type":"file_version","id":"158227338595","sha1":"2e2124c0d6589dd05d03a854b9c5c3a68bbc4501"},"sequence_id":"17","etag":"17","sha1":"2e2124c0d6589dd05d03a854b9c5c3a68bbc4501","name":"2-17 Upcoming ScholarSphere changes.boxnote"},{"type":"file","id":"75228871930","file_version":{"type":"file_version","id":"79668751214","sha1":"43cd4ac728cef7767dc132c26b181133d867d78f"},"sequence_id":"1","etag":"1","sha1":"43cd4ac728cef7767dc132c26b181133d867d78f","name":"99bottles (1).epub"},{"type":"file","id":"72329914177","file_version":{"type":"file_version","id":"76429987577","sha1":"a3310fdad0e6c9654b19d88b35318b8cdc246379"},"sequence_id":"2","etag":"2","sha1":"a3310fdad0e6c9654b19d88b35318b8cdc246379","name":"Development Team Projects and Milestones (not downloaded).xlsx"},{"type":"file","id":"74507436394","file_version":{"type":"file_version","id":"78854145518","sha1":"589ab64efb1ba49537074fd2c56e1570a24a47b5"},"sequence_id":"7","etag":"7","sha1":"589ab64efb1ba49537074fd2c56e1570a24a47b5","name":"Development Team Projects and Milestones - Editable.xlsx"},{"type":"file","id":"72324078305","file_version":{"type":"file_version","id":"76423451525","sha1":"42c0a5a34717cd17e315653643b61d23e94b7cd7"},"sequence_id":"3","etag":"3","sha1":"42c0a5a34717cd17e315653643b61d23e94b7cd7","name":"Development Team Projects and Milestones.xlsx"},{"type":"file","id":"106651625938","file_version":{"type":"file_version","id":"114805197783","sha1":"0c1c90a0186bd3934ce3877e092a228dc1568e93"},"sequence_id":"2","etag":"2","sha1":"0c1c90a0186bd3934ce3877e092a228dc1568e93","name":"Digital Scholarship and Repository Development (DSRD) Org Chart 2016.pdf"},{"type":"file","id":"76960974625","file_version":{"type":"file_version","id":"106919307872","sha1":"74608bfb532feff774502c6132eafe9acb1e5217"},"sequence_id":"162","etag":"162","sha1":"74608bfb532feff774502c6132eafe9acb1e5217","name":"Equipment.boxnote"},{"type":"file","id":"68362464289","file_version":{"type":"file_version","id":"101137863811","sha1":"40a0a3f98926874f1ee62fd522621a4408e0058c"},"sequence_id":"8","etag":"8","sha1":"40a0a3f98926874f1ee62fd522621a4408e0058c","name":"migrationDesign.pptx"},{"type":"file","id":"99028795390","file_version":{"type":"file_version","id":"107183805224","sha1":"7044bd7f0892f915b77b914430c2915161f942d9"},"sequence_id":"37","etag":"37","sha1":"7044bd7f0892f915b77b914430c2915161f942d9","name":"Onboarding.boxnote"},{"type":"file","id":"134865535934","file_version":{"type":"file_version","id":"143971901576","sha1":"32cc33b2cd5cc46f0a3fb924b4779cc387a81018"},"sequence_id":"1","etag":"1","sha1":"32cc33b2cd5cc46f0a3fb924b4779cc387a81018","name":"passenger-test.boxnote"},{"type":"file","id":"92102699797","file_version":{"type":"file_version","id":"98754405909","sha1":"053b762f6d5752c261ef7ff6a3d776853cdb2ca3"},"sequence_id":"1","etag":"1","sha1":"053b762f6d5752c261ef7ff6a3d776853cdb2ca3","name":"sas_development_libraries_mou_2016_08_01.docx"},{"type":"file","id":"22182934895","file_version":{"type":"file_version","id":"50126669941","sha1":"8ca396b5b26ff90d625ea3a49f0cc69ad844476b"},"sequence_id":"41","etag":"41","sha1":"8ca396b5b26ff90d625ea3a49f0cc69ad844476b","name":"TimeBox.xlsx"}],"offset":0,"limit":100,"order":[{"by":"type","direction":"ASC"},{"by":"name","direction":"ASC"}]}}'
171
+ end
172
+ let(:folders_items_response_body) do
173
+ '{"total_count":17,"entries":[{"type":"folder","id":"2459974427","etag":"0","name":"Apps&Int","size":14341346,"created_at":"2014-09-17T13:42:30-07:00"},{"type":"folder","id":"11217040834","etag":"0","name":"Credentials","size":12603,"created_at":"2016-09-07T08:37:23-07:00"},{"type":"folder","id":"5662231069","etag":"0","name":"DevOps Presentation","size":128158633,"created_at":"2015-12-07T05:51:08-08:00"},{"type":"folder","id":"8648394509","etag":"0","name":"old","size":117232,"created_at":"2016-06-30T08:03:46-07:00"},{"type":"folder","id":"12445061821","etag":"0","name":"Ops Plan","size":6181924,"created_at":"2016-11-17T06:52:58-08:00"},{"type":"file","id":"136917954839","etag":"17","name":"2-17 Upcoming ScholarSphere changes.boxnote","size":1768,"created_at":"2017-02-17T09:27:57-08:00"},{"type":"file","id":"75228871930","etag":"1","name":"99bottles (1).epub","size":1013573,"created_at":"2016-07-21T03:53:01-07:00"},{"type":"file","id":"72329914177","etag":"2","name":"Development Team Projects and Milestones (not downloaded).xlsx","size":20812,"created_at":"2016-06-30T09:10:36-07:00"},{"type":"file","id":"74507436394","etag":"7","name":"Development Team Projects and Milestones - Editable.xlsx","size":21001,"created_at":"2016-07-15T11:08:54-07:00"},{"type":"file","id":"72324078305","etag":"3","name":"Development Team Projects and Milestones.xlsx","size":22410,"created_at":"2016-06-30T08:31:56-07:00"},{"type":"file","id":"106651625938","etag":"2","name":"Digital Scholarship and Repository Development (DSRD) Org Chart 2016.pdf","size":17677,"created_at":"2016-11-30T08:27:58-08:00"},{"type":"file","id":"76960974625","etag":"162","name":"Equipment.boxnote","size":10140,"created_at":"2016-08-03T12:22:39-07:00"},{"type":"file","id":"68362464289","etag":"8","name":"migrationDesign.pptx","size":47751,"created_at":"2016-06-03T03:56:54-07:00"},{"type":"file","id":"99028795390","etag":"37","name":"Onboarding.boxnote","size":4465,"created_at":"2016-10-24T11:41:47-07:00"},{"type":"file","id":"134865535934","etag":"1","name":"passenger-test.boxnote","size":4988,"created_at":"2017-02-13T10:47:38-08:00"},{"type":"file","id":"92102699797","etag":"1","name":"sas_development_libraries_mou_2016_08_01.docx","size":134018,"created_at":"2016-08-16T07:32:53-07:00"},{"type":"file","id":"22182934895","etag":"41","name":"TimeBox.xlsx","size":21864,"created_at":"2014-10-23T08:22:16-07:00"}],"offset":0,"limit":1000,"order":[{"by":"type","direction":"ASC"},{"by":"name","direction":"ASC"}]}'
174
+ end
146
175
 
147
- its(:name) { is_expected.to eq('..') }
148
- its(:location) { is_expected.to be_empty }
149
- its(:id) { is_expected.to be_kind_of(Pathname) }
150
- it { is_expected.to be_container }
176
+ before do
177
+ stub_request(
178
+ :get, "https://api.box.com/2.0/folders/#{folder_id}"
179
+ ).to_return(
180
+ body: folders_response_body,
181
+ status: 200,
182
+ headers: {
183
+ 'Content-Type' => 'application/json'
184
+ }
185
+ )
186
+ stub_request(
187
+ :get, "https://api.box.com/2.0/folders/#{folder_id}/items?fields=name,size,created_at&limit=99999&offset=0"
188
+ ).to_return(
189
+ body: folders_items_response_body,
190
+ status: 200,
191
+ headers: {
192
+ 'Content-Type' => 'application/json'
193
+ }
194
+ )
151
195
  end
152
196
 
153
197
  describe 'the second item' do
@@ -172,17 +216,53 @@ describe BrowseEverything::Driver::Box, vcr: { cassette_name: 'box', record: :no
172
216
  end
173
217
 
174
218
  describe '#link_for' do
175
- before { provider.token = token }
219
+ before do
220
+ provider.token = token
221
+
222
+ # Initial request for metadata
223
+ stub_request(
224
+ :get, "https://api.box.com/2.0/files/#{file_id}"
225
+ ).to_return(
226
+ body: files_response_body,
227
+ status: 200,
228
+ headers: {
229
+ 'Content-Type' => 'application/json'
230
+ }
231
+ )
232
+
233
+ # Request for the content
234
+ stub_request(
235
+ :get, "https://api.box.com/2.0/files/#{file_id}/content"
236
+ ).to_return(
237
+ status: 302,
238
+ headers: {
239
+ 'location' => files_response_location
240
+ }
241
+ )
242
+ end
243
+ let(:link) { provider.link_for(file_id) }
176
244
 
177
245
  context 'with a file from the root directory' do
178
- let(:link) { provider.link_for('25581309763') }
246
+ let(:files_response_location) do
247
+ 'https://dl.boxcloud.com/d/1/B7Qd7B_iwPHTU4-71W2qYoTbvAaHCPzNsy5WTFHj5XpbmydlF8ud_0n7Ji7zswdU3Kg0patL8EUXCR3cpPw1PZjp-_a1t6MoH-tX3eQeCAR080Hr-yQaEmLQ8dULnnlOhYHeYwPuRp-0gCcXCF5w3O3bE6ZHgML3SCQchPoJQlsfvcYwXZyPRFEVRNUo7qou5X9dbkMCJGmB0CsvqKTXfEs8bqbmRV4hZ5qpJbD0Jer1m4vsqu8h5VkBdMIcgFMn_D9TheZOrmQdg8ExZZVPJ7X8QjFjI707WwIl7CNYkmocCdAJnbYQljFMiQsp0wF0etUqoiskNnaJBS3NagvtvSKaX3TVfiXa87CHDwPiQ3PNJE32d49eKcBK9nLLigoX3SJOkJqMqUSXO_UAxl0bO0EszCNpaWsiQwWiG2jjB5YBfDwQbmfuSTCBPkhDjIH3S3n5cadk4H_8rvgHshYBXNJd2NshgPsYt1XIkE8qj4WznzwayZoi_2k5x4liFvs2F91anj0bPAW2Mzeyz0Pi49mythoH7Rrq_i0sbYDt3VJNyCB0wqs8xUCa38Z6NocTKrKtFHrNSyM2-g5nWsAIwGeG4L4kZ_qIq8nNL49LsntvpFmhogONBozQQCvoEj0WXqhLCxxwT4U-pZ5rCYDt6dpoNlmYv962wXUzg_s21CO96J1o9-_xKl9JxmbWPf0DDJ35gCBFWMhL6BTaLckbBrybx41luHjjDuv72CxfsqsabdyW2yDN3uoBAcXIXD7QUOACPXKHvC98kL9aXL9o9X-zt89vUP61ijizsjtoI9RQc4CrjerfnxC7jS-ER3w2nwkgOEr1wkdEvq4QabcVlyixgrRxKTmzHXa0JGfmpLdEQ821Sgi7QHOpa0l5CSZTQycnWHoMKn4f_xJo5WZLmkmNgkE2DRsok0xGVUK_lNKjrt_N9mPVAdeeXLjSyoSol2_ugU79ELQSHJKKyTFAEJOscUSseg5MtWrIOLKQY6NlAaE0Ckn7c_LX4MYaSj83F-sZouvwSRNVbTklMNkC6j2fy4kr8_T3eb_9-Df94B1867kSJzt7TjXSAxz_p9PbRuj7eY1NW15zjxtOPQpk/download'
248
+ end
249
+ let(:files_response_body) do
250
+ '{"type":"file","id":"25581309763","file_version":{"type":"file_version","id":"23869158869","sha1":"4604bbe44fdcdd4afef3c666cf582e3773960954"},"sequence_id":"1","etag":"1","sha1":"4604bbe44fdcdd4afef3c666cf582e3773960954","name":"failed.tar.gz","description":"","size":28650839,"path_collection":{"total_count":1,"entries":[{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files"}]},"created_at":"2015-01-29T05:18:43-08:00","modified_at":"2015-01-29T05:18:43-08:00","trashed_at":null,"purged_at":null,"content_created_at":"2015-01-17T05:59:48-08:00","content_modified_at":"2015-01-17T06:00:03-08:00","created_by":{"type":"user","id":"225383863","name":"ADAM GARNER WEAD","login":"agw13@psu.edu"},"modified_by":{"type":"user","id":"225383863","name":"ADAM GARNER WEAD","login":"agw13@psu.edu"},"owned_by":{"type":"user","id":"225383863","name":"ADAM GARNER WEAD","login":"agw13@psu.edu"},"shared_link":{"url":"https:\/\/psu.box.com\/s\/w89hg6kf73q8fn1ww51cj92ohb6piyet","download_url":"https:\/\/psu.box.com\/shared\/static\/w89hg6kf73q8fn1ww51cj92ohb6piyet.gz","vanity_url":null,"effective_access":"open","is_password_enabled":false,"unshared_at":null,"download_count":1,"preview_count":0,"access":"open","permissions":{"can_download":true,"can_preview":true}},"parent":{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files"},"item_status":"active"}'
251
+ end
252
+ let(:file_id) { '25581309763' }
179
253
 
180
254
  specify { expect(link[0]).to start_with('https://dl.boxcloud.com/d/1') }
181
255
  specify { expect(link[1]).to have_key(:expires) }
182
256
  end
183
257
 
184
258
  context 'with a file from the SaS - Development Team directory' do
185
- let(:link) { provider.link_for('76960974625') }
259
+ let(:files_response_location) do
260
+ 'https://dl.boxcloud.com/d/1/lCA2dDrIV1QAvpQLU7_mkJ0bt2Soa1dLRT6FOzmF37EfJgjRmCO-rZ0VFyKCtoHgPzRoCIHgx-IWCoV8cvtfTX4Yw--RmBLBV9f4JsK6i3LMRKQzgDMxsMu97RSmuMagV-GayR8uO6NGFBtoX81yujebVY-JRB7cxhPU0fbCxAzAnv1711_IUs6YXwhWc-rNFHrNjPsUnJLqw0soQPZqF3Q5irxJLu7traVIeoeuGSfhw-7G-qfqu4CIFonC4ktwwh8jMgN9KW712kRg61moLG6Aa6FTbdCCSt_jCwvQFVGqCz_VivfzG2_BHBqh4IhIB76DmF1ISM-jD9VToUwYfscg6BgC2fqGj6OycsuYr3v3EE0gHlPw_X2rJnq9J2M9plnnhqBvXEwoUXDqyGPvSqWBeQvrrTYfvqj7fG48tUr7RKOytc_K0B4aw9hgGUk3EaifSVWzYvXzoXBp27HFHPsssvIK8fXoSU2J3HCEsGhIDFzu3cvXyPZJV_Co1_LvivWM0AGjXhyoC8PNO5qmtrZFgCob3KlZ8BEI1yJfX_0K8wpocUJP95eBNutBhWa2DEvCK6R5OG-Z0XwrJu8XFRwPcIl3_7lSsIhsQlYA7MoJer7hhwVGAl3kPP-bFsw1et66UM6KHG2FdN2xKP10DYFqR_JrShPP8DQ-ik9-lKej_8LTfiHdf0YbkdMNKzBYlXZsiQNwd3VXdRo1Z4Uhza_XtTDcfH0uxRQyYRecHr-5lEn5iUfV1199GrTsLkcOb9ONNSTFPKW15XCLpgJm6ylSpG2JSZ6zWsGL5hUzdvMytwBCMpIj84UZuwo2RTH1ZDUJYjmHRX11rDnwe2zKMz4woYIA8RjhnYEj6d13BeBz9Fy4GgR90jmM5xHIv9fiAG_b99fpDuYvT-tccN4pdrxPf0P-kCjYAHBt7kY7ToaMWcnOf1nGdLP0oaCGHhAzN0iurjRTLRi2S4N1hsWxjoMuQqayEq15QhRujy2lTZX_XyBgrU2ZodkNsQUlaWcJ6aFT8bh48DtyQvt_xfm4jqmStageFKbydyoB8BpP6oYFAMeFlkS4A6LnXJCzpO8Q../download'
261
+ end
262
+ let(:files_response_body) do
263
+ '{"type":"file","id":"76960974625","file_version":{"type":"file_version","id":"106919307872","sha1":"74608bfb532feff774502c6132eafe9acb1e5217"},"sequence_id":"162","etag":"162","sha1":"74608bfb532feff774502c6132eafe9acb1e5217","name":"Equipment.boxnote","description":"Listing equipment we currently have","size":10140,"path_collection":{"total_count":2,"entries":[{"type":"folder","id":"0","sequence_id":null,"etag":null,"name":"All Files"},{"type":"folder","id":"2459961273","sequence_id":"0","etag":"0","name":"SaS - Development Team"}]},"created_at":"2016-08-03T12:22:39-07:00","modified_at":"2016-10-26T12:40:09-07:00","trashed_at":null,"purged_at":null,"content_created_at":"2016-08-03T12:22:39-07:00","content_modified_at":"2016-10-26T12:40:09-07:00","created_by":{"type":"user","id":"212771336","name":"NICOLE M. GAMPE","login":"nmg110@psu.edu"},"modified_by":{"type":"user","id":"208208274","name":"JUSTIN R PATTERSON","login":"jrp22@psu.edu"},"owned_by":{"type":"user","id":"191882215","name":"Daniel Coughlin","login":"dmc186@psu.edu"},"shared_link":{"url":"https:\/\/psu.box.com\/s\/uolieeszpwglsv0ipwij9ws36rrepvba","download_url":"https:\/\/psu.box.com\/shared\/static\/uolieeszpwglsv0ipwij9ws36rrepvba.boxnote","vanity_url":null,"effective_access":"open","is_password_enabled":false,"unshared_at":null,"download_count":24,"preview_count":0,"access":"open","permissions":{"can_download":true,"can_preview":true}},"parent":{"type":"folder","id":"2459961273","sequence_id":"0","etag":"0","name":"SaS - Development Team"},"item_status":"active"}'
264
+ end
265
+ let(:file_id) { '76960974625' }
186
266
 
187
267
  specify { expect(link[0]).to start_with('https://dl.boxcloud.com/d/1') }
188
268
  specify { expect(link[1]).to have_key(:expires) }
@@ -2,7 +2,7 @@
2
2
 
3
3
  include BrowserConfigHelper
4
4
 
5
- describe BrowseEverything::Driver::Dropbox, vcr: { cassette_name: 'dropbox', record: :none } do
5
+ describe BrowseEverything::Driver::Dropbox do
6
6
  let(:browser) { BrowseEverything::Browser.new(url_options) }
7
7
  let(:provider) { browser.providers['dropbox'] }
8
8
  let(:provider_yml) do
@@ -11,9 +11,22 @@ describe BrowseEverything::Driver::Dropbox, vcr: { cassette_name: 'dropbox', rec
11
11
  client_secret: 'client-secret'
12
12
  }
13
13
  end
14
+ let(:oauth_response_body) do
15
+ '{"access_token": "test-access-token", "token_type": "bearer", "uid": "test-user-id", "account_id": "dbid:id"}'
16
+ end
14
17
 
15
18
  before do
16
19
  stub_configuration
20
+
21
+ stub_request(
22
+ :post, 'https://api.dropboxapi.com/oauth2/token'
23
+ ).to_return(
24
+ body: oauth_response_body,
25
+ status: 200,
26
+ headers: {
27
+ 'Content-Type' => 'text/javascript'
28
+ }
29
+ )
17
30
  end
18
31
 
19
32
  after do
@@ -22,11 +35,11 @@ describe BrowseEverything::Driver::Dropbox, vcr: { cassette_name: 'dropbox', rec
22
35
 
23
36
  describe '#validate_config' do
24
37
  it 'raises and error with an incomplete configuration' do
25
- expect { BrowseEverything::Driver::Dropbox.new({}) }.to raise_error(BrowseEverything::InitializationError)
38
+ expect { described_class.new({}) }.to raise_error(BrowseEverything::InitializationError)
26
39
  end
27
40
 
28
41
  it 'raises and error with a configuration without a client secret' do
29
- expect { BrowseEverything::Driver::Dropbox.new(client_id: 'test-client-id') }.to raise_error(BrowseEverything::InitializationError)
42
+ expect { described_class.new(client_id: 'test-client-id') }.to raise_error(BrowseEverything::InitializationError)
30
43
  end
31
44
  end
32
45
 
@@ -40,11 +53,18 @@ describe BrowseEverything::Driver::Dropbox, vcr: { cassette_name: 'dropbox', rec
40
53
 
41
54
  context 'with a valid configuration' do
42
55
  let(:driver) { described_class.new(provider_yml) }
56
+ let(:connector_response_url_options) do
57
+ {
58
+ protocol: 'http://',
59
+ host: 'test.host',
60
+ port: 80
61
+ }
62
+ end
43
63
 
44
- before { driver.connect({ code: 'code' }, {}) }
64
+ before { driver.connect({ code: 'code' }, {}, connector_response_url_options) }
45
65
 
46
66
  describe '#auth_link' do
47
- subject { driver.auth_link }
67
+ subject { driver.auth_link(connector_response_url_options) }
48
68
 
49
69
  it { is_expected.to start_with('https://www.dropbox.com/oauth2/authorize') }
50
70
  end
@@ -58,6 +78,23 @@ describe BrowseEverything::Driver::Dropbox, vcr: { cassette_name: 'dropbox', rec
58
78
  describe '#contents' do
59
79
  context 'when in the root folder' do
60
80
  let(:contents) { driver.contents }
81
+ let(:list_folder_response) do
82
+ '{"entries": [{".tag": "folder", "name": "Photos", "path_lower": "/photos", "path_display": "/Photos", "id": "id:XAAAAAAAAAALA"}, {".tag": "file", "name": "Getting Started.pdf", "path_lower": "/getting started.pdf", "path_display": "/Getting Started.pdf", "id": "id:XAAAAAAAAAAKg", "client_modified": "2012-11-10T18:33:28Z", "server_modified": "2012-11-10T18:33:27Z", "rev": "60b9427f2", "size": 249159, "content_hash": "c3dfdd86981548e48bc8efb6c4162c76ba961ec92e60f6ba26189068a41fcaf2"}], "cursor": "AAFu-_dOPQTQnqOIb9JklCPYSxWtNRrBBOU4nNkY78wTCc-ktCP4MtIoN1nmOESizkoue2dpu3FbMwDM6BQbgkLObH_Ge-H0BYaPwjfLk5cUHZHd1swkMYGLWELfX_PIHH9hCmU0C8sUL2EJ-7y6BcRFpdOvPmxiu6azVyCx_Il7kA", "has_more": false}'
83
+ end
84
+
85
+ before do
86
+ stub_request(
87
+ :post, 'https://api.dropboxapi.com/2/files/list_folder'
88
+ ).with(
89
+ body: '{"recursive":false,"include_media_info":false,"include_deleted":false,"path":""}'
90
+ ).to_return(
91
+ body: list_folder_response,
92
+ status: 200,
93
+ headers: {
94
+ 'Content-Type' => 'application/json'
95
+ }
96
+ )
97
+ end
61
98
 
62
99
  it 'retrieves all folders the root folders' do
63
100
  expect(contents).not_to be_empty
@@ -75,6 +112,17 @@ describe BrowseEverything::Driver::Dropbox, vcr: { cassette_name: 'dropbox', rec
75
112
 
76
113
  describe '#link_for' do
77
114
  subject(:link_args) { driver.link_for('/Getting Started.pdf') }
115
+ before do
116
+ stub_request(
117
+ :post, 'https://content.dropboxapi.com/2/files/download'
118
+ ).to_return(
119
+ body: '{"name": "Getting Started.pdf", "path_lower": "/getting started.pdf", "path_display": "/Getting Started.pdf", "id": "id:XAAAAAAAAAAKg", "client_modified": "2012-11-10T18:33:28Z", "server_modified": "2012-11-10T18:33:27Z", "rev": "60b9427f2", "size": 249159, "content_hash": "c3dfdd86981548e48bc8efb6c4162c76ba961ec92e60f6ba26189068a41fcaf2"}',
120
+ status: 200,
121
+ headers: {
122
+ 'Content-Type' => 'application/json'
123
+ }
124
+ )
125
+ end
78
126
 
79
127
  it 'provides link arguments for accessing the file' do
80
128
  expect(link_args.first).to be_a String