BrowseEverything
What is BrowseEverything?
This Gem allows your rails application to access user files from cloud storage. Currently there are drivers implemented for Dropbox, Google Drive, Box, Amazon S3, and a server-side directory share.
The gem uses OAuth to connect to a user's account and generate a list of single use urls that your application can then use to download the files.
This gem does not depend on hydra-head
Technical Debt/Legacy warning
This project has been receiving very limited maintenance for at least 2-4 years now -- just enough to keep it working for present users. Caution is indicated in considering adoption for new projects.
Known issues (Nov 2024)
-
The S3 local file system adapters are known working. It's not clear if any other adapters are working properly -- or if the browse_everything architecture as is is sufficient to support OAuth2 integration flows that may be required to get them working.
-
CSS and Javascript were both written for use with sprockets asset pipeline, and are currently only tested with sprockets -- even in Rails 8, where
rails new
cannot generate a sprockets using app.- For use with Rails 8, you could consider adding sprockets to your app manually, or copying browse_everything JS and CSS assets into your local app and including them that way. The browse_everything installer is not capable of doing this in an automated fashion.
-
Good news: The
bootstrap4
CSS is tentatively demonstrated working with bootstrap 5 too. -
JS depends on JQuery, which is unfortunate in 2024. As well as a vendored copy of a jquery.treetable plugin.
Possible path to a revived gem
If there are interest and resources, assuming a major version release.
-
Rewrite JS from the ground up to be vanilla JS without JQuery.
- And useable by either
importmap-rails
or an npm-based rails JS bundler.
- And useable by either
-
Figure out what adapters actually work, drop those that don't work from the gem.
- Possibly find adapters in PR's or forks that work and can be added.
-
Testing overhaul
- Adapters have their network communication with cloud mocked for good reason, but that makes them false negative and unreliable at detecting breakage.
- Testing is done with an in-repo Rails app instead of engine_cart, which is probably reasonable, but that makes it harder to really test integration with differnet rails versions or test the installer works, as Rails has had churn in JS. go back to engine_cart, or consider combustion
Product Owner & Maintenance
browse-everything
was a Core Component of the Samvera Community. Given a decline in available labor required for maintenance, this project no longer has a dedicated Product Owner. The documentation for what this means can be found here.
Product Owner
Vacant
Until a Product Owner has been identified, we ask that you please direct all requests for support, bug reports, and general questions to the #dev
Channel on the Samvera Slack.
Getting Started
Supported Ruby Releases
Currently, the following releases of Ruby are tested:
- 3.1
- 3.0
- 2.7
- 2.6
Supported Rails Releases
The supported Rail releases follow those specified by the security policy of the Rails Community. As is the case with the supported Ruby releases, it is recommended that one upgrades from any Rails release no longer receiving security updates.
- 7.1
- 7.0
- 6.1
- 6.0
- 5.2
- 5.1
Installation
Add this lines to your application's Gemfile:
gem 'jquery-rails'
gem 'browse-everything'
And then execute:
$ bundle
Or install it yourself as:
$ gem install browse-everything
Configuring the gem in your host app
After installing the gem, run the generator
$ rails g browse_everything:install
This generator will set up the config/browse_everything_providers.yml file and add the browse-everything engine to your application's routes.
If you prefer not to use the generator, or need info on how to set up providers in the browse_everything_providers.yml, use the info on Configuring browse-everything.
Browse-everything depends on bootstrap, it can work with bootstrap 3 or bootstrap 4.
CSS
For bootstrap3 support, your app should include the bootstrap-sass gem in it's Gemfile, and following the install directions for bootstrap-sass, should have @import 'bootstrap-sprockets'
and @import 'bootstrap'
in it's application.scss. After those lines, add @import "browse_everything/browse_everything_bootstrap3";
to your application.scss.
For bootstrap4 support, your app should include the bootstrap gem in it's Gemfile, and following the install directions for that gem should have @import "bootstrap";
in it's application.scss. After that line, add @import 'browse_everything/browse_everything_bootstrap4'
to your application.scss.
Javascript
In app/assets/javascripts/application.js
include jquery and the BrowseEverything
//= require jquery
//= require browse_everything
(Same for bootstrap3 or bootstrap 4)
Migration CSS inclusion from pre-1.0
If your app has installed a previous version of browse-everything, you may have a generated file at ./app/assets/stylesheets/browse_everything.scss
, which has a line in it @import "browse_everything/browse_everything";
. That import should no longer be used; it can be changed to @import "browse_everything/browse_everything_bootstrap3"
instead.
However, we also recommend merging the contents of this file into your main application.scss
file, as documented in the current install instructions. With the separate generated file with bootstrap imports, you may likely be including bootstrap CSS in your generated CSS bundle twice, if you also have that import in your main application.scss already.
Usage
Adding Providers
In order to connect to a provider like Dropbox, Google Drive, or Box, you must provide API keys in config/browse_everything_providers.yml. For info on how to edit this file, see Configuring browse-everything
Views
browse-everything can be triggered in two ways -- either via data attributes in an HTML tag or via JavaScript. Either way, it accepts the same options:
Options
Name | Type | Default | Description |
---|---|---|---|
route | path (required) | '' | The base route of the browse-everything engine. |
target | xpath or jQuery | null | A form object to add the results to as hidden fields. |
context | text | null | App-specific context information (passed with each request) |
accept | MIME mask | / | A list of acceptable MIME types to browse (e.g., 'video/*') |
If a target
is provided, browse-everything will automatically convert the JSON response to a series of hidden form fields
that can be posted back to Rails to re-create the array on the server side.
Via data attributes
To trigger browse-everything using data attributes, set the data-toggle attribute to "browse-everything" on the HTML tag. This tells the javascript where to attach the browse-everything behaviors. Pass in the options using the data-route and data-target attributes, as in data-target="#myForm"
.
For example:
<button type="button" data-toggle="browse-everything" data-route="<%=browse_everything_engine.root_path%>"
data-target="#myForm" class="btn btn-large btn-success" id="browse">Browse!</button>
Via JavaScript
To trigger browse-everything via javascript, use the .browseEverything() method to attach the behaviors to DOM elements.
$('#browse').browseEverything(options)
The options argument should be a JSON object with the route and (optionally) target values set. For example:
$('#browse').browseEverything({
route: "/browse",
target: "#myForm"
})
See JavaScript Methods for more info on using javascript to trigger browse-everything.
The Results (Data Structure)
browse-everything returns a JSON data structure consisting of an array of URL specifications. Each URL specification is a plain object with the following properties:
Property | Description |
---|---|
url | The URL of the selected remote file. |
auth_header | Any headers that need to be added to the request in order to access the remote file. |
expires | The expiration date/time of the specified URL. |
file_name | The base name (filename.ext) of the selected file. |
For example, after picking two files from dropbox,
If you initialized browse-everything via JavaScript, the results data passed to the .done()
callback will look like this:
[
{
"url": "https://dl.dropbox.com/fake/filepicker-demo.txt.txt",
"expires": "2014-03-31T20:37:36.214Z",
"file_name": "filepicker-demo.txt.txt"
}, {
"url": "https://dl.dropbox.com/fake/Getting%20Started.pdf",
"expires": "2014-03-31T20:37:36.731Z",
"file_name": "Getting Started.pdf"
}
]
See JavaScript Methods for more info on using javascript to trigger browse-everything.
If you initialized browse-everything via data-attributes and set the target option (via the data-target attribute or via the target option on the javascript method), the results data be written as hidden fields in the <form>
you've specified as the target. When the user submits that form, the results will look like this:
"selected_files" => {
"0"=>{
"url"=>"https://dl.dropbox.com/fake/filepicker-demo.txt.txt",
"expires"=>"2014-03-31T20:37:36.214Z",
"file_name"=>"filepicker-demo.txt.txt"
},
"1"=>{
"url"=>"https://dl.dropbox.com/fake/Getting%20Started.pdf",
"expires"=>"2014-03-31T20:37:36.731Z",
"file_name"=>"Getting Started.pdf"
}
}
Retrieving Files
The BrowseEverything::Retriever
class has two methods, #retrieve
and #download
, that
can be used to retrieve selected content. #retrieve
streams the file by yielding it, chunk
by chunk, to a block, while #download
saves it to a local file.
Given the above response data:
retriever = BrowseEverything::Retriever.new
download_spec = params['selected_files']['1']
# Retrieve the file, yielding each chunk to a block
retriever.retrieve(download_spec) do |chunk, retrieved, total|
# do something with the `chunk` of data received, and/or
# display some progress using `retrieved` and `total` bytes.
end
# Download the file. If `target_file` isn't specified, the
# retriever will create a tempfile and return the name.
retriever.download(download_spec, target_file) do |filename, retrieved, total|
# The block is still useful for showing progress, but the
# first argument is the filename instead of a chunk of data.
end
Examples
See spec/support/app/views/file_handler/index.html
for an example use case. You can also run rake app:generate
to
create a fully-functioning demo app in spec/internal
(though you will have to create
spec/internal/config/browse_everything.providers.yml
file with your own configuration info.)
Development Testing
This is a Rails Engine which is tested using an in-repo "dummy" app, in the style of skeletons
generated by rails plugin new --full
.
Rails utilities
This gives you Rails-provided tools you can run in project home dir, like: ./bin/rails console
, ./bin/rails server
(to start the dummy app in dev mode), bundle exec rake db:drop db:create db:migrate
(db management in dummy app).
Test suite
Full CI/test suite may be executed with the following invocation:
bundle exec rake
Or individually, bundle exec rubocop
, bundle exec rspec
.
Testing with different versions of dependencies
You can test with different versions of rails by setting ENV variable RAILS_VERSION
to a specific version like "6.1.2"
or "7.0.0"
, perhaps by export RAILS_ENV=7.0.0
to set it in your shell session.
After changing RAILS_VERSION
you may have to run rm Gemfile.lock
and bundle install
again. If you get a Bundler could not find compatible versions...
error, for instance.
Help
The Samvera community is here to help. Please see our support guide.
Acknowledgments
This software has been developed by and is brought to you by the Samvera community. Learn more at the Samvera website.