browse-everything 0.1.0

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 (59) hide show
  1. data/.gitignore +19 -0
  2. data/.travis.yml +6 -0
  3. data/CONTRIBUTING.md +113 -0
  4. data/Gemfile +4 -0
  5. data/HISTORY.md +2 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +164 -0
  8. data/Rakefile +10 -0
  9. data/app/.DS_Store +0 -0
  10. data/app/assets/javascripts/browse_everything.js +3 -0
  11. data/app/assets/javascripts/browse_everything/behavior.js.coffee +110 -0
  12. data/app/assets/stylesheets/browse_everything.css.scss +82 -0
  13. data/app/controllers/browse_everything_controller.rb +74 -0
  14. data/app/helpers/browse_everything_helper.rb +11 -0
  15. data/app/views/.DS_Store +0 -0
  16. data/app/views/browse_everything/_auth.html.erb +3 -0
  17. data/app/views/browse_everything/_files.html.erb +12 -0
  18. data/app/views/browse_everything/_providers.html.erb +10 -0
  19. data/app/views/browse_everything/auth.html.erb +7 -0
  20. data/app/views/browse_everything/index.html.erb +28 -0
  21. data/app/views/browse_everything/resolve.html.erb +1 -0
  22. data/app/views/browse_everything/show.html.erb +9 -0
  23. data/app/views/layouts/browse_everything.html.erb +11 -0
  24. data/browse-everything.gemspec +40 -0
  25. data/config/locales/en_browse_everything.yml +13 -0
  26. data/config/routes.rb +6 -0
  27. data/lib/browse-everything.rb +1 -0
  28. data/lib/browse_everything.rb +37 -0
  29. data/lib/browse_everything/browser.rb +25 -0
  30. data/lib/browse_everything/driver/base.rb +55 -0
  31. data/lib/browse_everything/driver/box.rb +90 -0
  32. data/lib/browse_everything/driver/drop_box.rb +74 -0
  33. data/lib/browse_everything/driver/file_system.rb +62 -0
  34. data/lib/browse_everything/driver/google_drive.rb +103 -0
  35. data/lib/browse_everything/driver/sky_drive.rb +132 -0
  36. data/lib/browse_everything/engine.rb +6 -0
  37. data/lib/browse_everything/file_entry.rb +19 -0
  38. data/lib/browse_everything/version.rb +3 -0
  39. data/spec/fixtures/file_system/dir_1/dir_3/file_3.m4v +0 -0
  40. data/spec/fixtures/file_system/dir_1/file_2.txt +1 -0
  41. data/spec/fixtures/file_system/dir_2/file_4.docx +1 -0
  42. data/spec/fixtures/file_system/file_1.pdf +0 -0
  43. data/spec/fixtures/vcr_cassettes/dropbox.yml +231 -0
  44. data/spec/rake/app_spec.rb +121 -0
  45. data/spec/spec_helper.rb +56 -0
  46. data/spec/spec_helper.rb.orig +47 -0
  47. data/spec/support/app/controllers/file_handler_controller.rb +8 -0
  48. data/spec/support/app/views/file_handler/index.html.erb +22 -0
  49. data/spec/support/config/browse_everything_providers.yml.example +15 -0
  50. data/spec/support/lib/generators/test_app_generator.rb +50 -0
  51. data/spec/unit/base_spec.rb +28 -0
  52. data/spec/unit/browser_spec.rb +76 -0
  53. data/spec/unit/drop_box_spec.rb +119 -0
  54. data/spec/unit/file_entry_spec.rb +44 -0
  55. data/spec/unit/file_system_spec.rb +85 -0
  56. data/spec/unit/sky_drive_spec.rb +58 -0
  57. data/tasks/browse-everything-dev.rake +63 -0
  58. data/tasks/ci.rake +7 -0
  59. metadata +419 -0
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/internal
19
+ browse_everything_providers.yml
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ - "2.0.0"
5
+ notifications:
6
+ irc: "irc.freenode.org#projecthydra"
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,113 @@
1
+ # How to Contribute
2
+
3
+ We want your help to make Project Hydra great.
4
+ There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
5
+
6
+ ## Hydra Project Intellectual Property Licensing and Ownership
7
+
8
+ All code contributors must have an Individual Contributor License Agreement (iCLA) on file with the Hydra Project Steering Group.
9
+ If the contributor works for an institution, the institution must have a Corporate Contributor License Agreement (cCLA) on file.
10
+
11
+ https://wiki.duraspace.org/display/hydra/Hydra+Project+Intellectual+Property+Licensing+and+Ownership
12
+
13
+ You should also add yourself to the `CONTRIBUTORS.md` file in the root of the project.
14
+
15
+ ## Contribution Tasks
16
+
17
+ * Reporting Issues
18
+ * Making Changes
19
+ * Submitting Changes
20
+ * Merging Changes
21
+
22
+ ### Reporting Issues
23
+
24
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
25
+ * Submit a [Github issue](./issues) by:
26
+ * Clearly describing the issue
27
+ * Provide a descriptive summary
28
+ * Explain the expected behavior
29
+ * Explain the actual behavior
30
+ * Provide steps to reproduce the actual behavior
31
+
32
+ ### Making Changes
33
+
34
+ * Fork the repository on GitHub
35
+ * Create a topic branch from where you want to base your work.
36
+ * This is usually the master branch.
37
+ * To quickly create a topic branch based on master; `git branch fix/master/my_contribution master`
38
+ * Then checkout the new branch with `git checkout fix/master/my_contribution`.
39
+ * Please avoid working directly on the `master` branch.
40
+ * You may find the [hub suite of commands](https://github.com/defunkt/hub) helpful
41
+ * Make commits of logical units.
42
+ * Your commit should include a high level description of your work in HISTORY.textile
43
+ * Check for unnecessary whitespace with `git diff --check` before committing.
44
+ * Make sure your commit messages are [well formed](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
45
+ * If you created an issue, you can close it by including "Closes #issue" in your commit message. See [Github's blog post for more details](https://github.com/blog/1386-closing-issues-via-commit-messages)
46
+
47
+ ```
48
+ Present tense short summary (50 characters or less)
49
+
50
+ More detailed description, if necessary. It should be wrapped to 72
51
+ characters. Try to be as descriptive as you can, even if you think that
52
+ the commit content is obvious, it may not be obvious to others. You
53
+ should add such description also if it's already present in bug tracker,
54
+ it should not be necessary to visit a webpage to check the history.
55
+
56
+ Include Closes #<issue-number> when relavent.
57
+
58
+ Description can have multiple paragraphs and you can use code examples
59
+ inside, just indent it with 4 spaces:
60
+
61
+ class PostsController
62
+ def index
63
+ respond_with Post.limit(10)
64
+ end
65
+ end
66
+
67
+ You can also add bullet points:
68
+
69
+ - you can use dashes or asterisks
70
+
71
+ - also, try to indent next line of a point for readability, if it's too
72
+ long to fit in 72 characters
73
+ ```
74
+
75
+ * Make sure you have added the necessary tests for your changes.
76
+ * Run _all_ the tests to assure nothing else was accidentally broken.
77
+ * When you are ready to submit a pull request
78
+
79
+ ### Submitting Changes
80
+
81
+ [Detailed Walkthrough of One Pull Request per Commit](http://ndlib.github.io/practices/one-commit-per-pull-request/)
82
+
83
+ * Read the article ["Using Pull Requests"](https://help.github.com/articles/using-pull-requests) on GitHub.
84
+ * Make sure your branch is up to date with its parent branch (i.e. master)
85
+ * `git checkout master`
86
+ * `git pull --rebase`
87
+ * `git checkout <your-branch>`
88
+ * `git rebase master`
89
+ * It is likely a good idea to run your tests again.
90
+ * Squash the commits for your branch into one commit
91
+ * `git rebase --interactive HEAD~<number-of-commits>` ([See Github help](https://help.github.com/articles/interactive-rebase))
92
+ * To determine the number of commits on your branch: `git log master..<your-branch> --oneline | wc -l`
93
+ * Squashing your branch's changes into one commit is "good form" and helps the person merging your request to see everything that is going on.
94
+ * Push your changes to a topic branch in your fork of the repository.
95
+ * Submit a pull request from your fork to the project.
96
+
97
+ ### Merging Changes
98
+
99
+ * It is considered "poor from" to merge your own request.
100
+ * Please take the time to review the changes and get a sense of what is being changed. Things to consider:
101
+ * Does the commit message explain what is going on?
102
+ * Does the code changes have tests? _Not all changes need new tests, some changes are refactorings_
103
+ * Does the commit contain more than it should? Are two separate concerns being addressed in one commit?
104
+ * Did the Travis tests complete successfully?
105
+ * If you are uncertain, bring other contributors into the conversation by creating a comment that includes their @username.
106
+ * If you like the pull request, but want others to chime in, create a +1 comment and tag a user.
107
+
108
+ # Additional Resources
109
+
110
+ * [General GitHub documentation](http://help.github.com/)
111
+ * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
112
+ * [Pro Git](http://git-scm.com/book) is both a free and excellent book about Git.
113
+ * [A Git Config for Contributing](http://ndlib.github.io/practices/my-typical-per-project-git-config/)
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in browse_everything.gemspec
4
+ gemspec
data/HISTORY.md ADDED
@@ -0,0 +1,2 @@
1
+ ### 0.1.0 (2013-09-24)
2
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Michael Klein
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,164 @@
1
+ [![Build Status](https://travis-ci.org/projecthydra/browse-everything.png?branch=master)](https://travis-ci.org/projecthydra/browse-everything)
2
+
3
+ # BrowseEverything
4
+
5
+ This Gem allows your rails application to access user files from cloud storage.
6
+ Currently there are drivers implemented for [DropBox](http://www.dropbox.com),
7
+ [Skydrive](https://skydrive.live.com/), [Google Drive](http://drive.google.com),
8
+ [Box](http://www.box.com), and a server-side directory share.
9
+
10
+ The gem uses [OAuth](http://oauth.net/) to connect to a user's account and
11
+ generate a list of single use urls that your application can then use to
12
+ download the files.
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ gem 'browse-everything'
19
+
20
+ And then execute:
21
+
22
+ $ bundle
23
+
24
+ Or install it yourself as:
25
+
26
+ $ gem install browse-everything
27
+
28
+ ## Usage
29
+
30
+ ### Configuration
31
+
32
+ To use the gem you will need to configure the providers by providing applcation keys that are required by each provider
33
+
34
+ An example config/browse_everything_providers.yml:
35
+
36
+ ```yaml
37
+ ---
38
+ file_system:
39
+ :home: /<location for server file drop>
40
+ sky_drive:
41
+ :client_id: <your client id>
42
+ :client_secret: <your client secret>
43
+ box:
44
+ :client_id: <your client id>
45
+ :client_secret: <your client secret>
46
+ drop_box:
47
+ :app_key: <your client id>
48
+ :app_secret: <your app secret>
49
+ google_drive:
50
+ :client_id: <your client id>
51
+ :client_secret: <your client secret>
52
+ ```
53
+
54
+ You must register your application with each cloud provider separately:
55
+
56
+ * Skydrive: [https://account.live.com/developers/applications/create](https://account.live.com/developers/applications/create)
57
+ * Dropbox: [https://www.dropbox.com/developers/apps/create](https://www.dropbox.com/developers/apps/create)
58
+ * Box: [https://app.box.com/developers/services/edit/](https://app.box.com/developers/services/edit/)
59
+ * GoogleDrive: [https://code.google.com/apis/console](https://code.google.com/apis/console)
60
+
61
+ ### CSS and JavaScript Modifications
62
+
63
+ Add `@import "browse_everything` to your application.css.scss
64
+
65
+ Add `//= require browse_everything` to your application.js
66
+
67
+ ### Routes
68
+
69
+ Mount the engine in your routes.rb
70
+
71
+ ```
72
+ mount BrowseEverything::Engine => '/browse'
73
+ ```
74
+
75
+ ### Views
76
+
77
+ browse-everything can be triggered in one of two ways:
78
+
79
+ #### Via data attributes
80
+
81
+ ```html
82
+ <button type="button" data-toggle="browse-everything" data-route="<%=browse_everything_engine.root_path%>"
83
+ data-target="#myForm" class="btn btn-large btn-success" id="browse">Browse!</button>
84
+ ```
85
+
86
+ #### Via JavaScript
87
+
88
+ ```javascript
89
+ $('#browse').browseEverything(options)
90
+ ```
91
+
92
+ #### Options
93
+
94
+ Options can be passed via data attributes or JavaScript. For data attributes, append the option name to `data-`,
95
+ as in `data-target="#myForm"`.
96
+
97
+ | Name | type | default | description |
98
+ |-----------------|-----------------|-----------------|----------------------------------------------------------------|
99
+ | route | path (required) | '' | The base route of the browse-everything engine. |
100
+ | target | xpath or jQuery | null | A form object to add the results to as hidden fields. |
101
+
102
+ If a `target` is provided, browse-everything will automatically convert the JSON response to a series of hidden form fields
103
+ that can be posted back to Rails to re-create the array on the server side.
104
+
105
+ #### Methods
106
+
107
+ ##### .browseEverything(options)
108
+
109
+ Attaches the browsing behavior to the click event of the receiver.
110
+
111
+ ```javascript
112
+ $('#browse').browseEverything({
113
+ route: "/browse",
114
+ target: "#myForm"
115
+ }).done(function(data) {
116
+ // User has submitted files; data contains an array of URLs and their options
117
+ }).cancel(function() {
118
+ // User cancelled the browse operation
119
+ }).fail(function(status, error, text) {
120
+ // URL retrieval experienced a techical failure
121
+ });
122
+ ```
123
+
124
+ ##### .browseEverything()
125
+
126
+ Returns the existing callback object for the receiver, allowing for a mix of data attribute and JavaScript modes.
127
+
128
+ ```html
129
+ <button type="button" data-toggle="browse-everything" data-route="/browse"
130
+ data-target="#myForm" class="btn btn-large btn-success" id="browse">Browse!</button>
131
+
132
+ <script>
133
+ $(document).ready(function() {
134
+ $('#browse').browseEverything().done(function(data) {
135
+ // Set the "done" callback for the already-defined #browse button
136
+ })
137
+ });
138
+ </script>
139
+ ```
140
+
141
+ #### Data Structure
142
+
143
+ browse-everything returns a JSON data structure consisting of an array of URL specifications. Each URL specification
144
+ is a plain object with the following properties:
145
+
146
+ | Property | Description |
147
+ |--------------------|--------------------------------------------------------------------------------------|
148
+ | url | The URL of the selected remote file. |
149
+ | auth_header | Any headers that need to be added to the request in order to access the remote file. |
150
+ | expires | The expiration date/time of the specified URL. |
151
+
152
+ ### Examples
153
+
154
+ See `spec/support/app/views/file_handler/index.html` for an example use case. You can also run `rake app:generate` to
155
+ create a fully-functioning demo app in `spec/internal` (though you will have to create
156
+ `spec/internal/config/browse_everything.providers.yml` file with your own configuration info.)
157
+
158
+ ## Contributing
159
+
160
+ 1. Fork it
161
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
162
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
163
+ 4. Push to the branch (`git push origin my-new-feature`)
164
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ Dir.glob('tasks/*.rake').each { |r| import r }
5
+
6
+ ENV["RAILS_ROOT"] ||= 'spec/internal'
7
+
8
+ require 'rspec/core/rake_task'
9
+
10
+ task :default => [:ci]
data/app/.DS_Store ADDED
Binary file
@@ -0,0 +1,3 @@
1
+ //= require jquery
2
+ //= require bootstrap
3
+ //= require browse_everything/behavior
@@ -0,0 +1,110 @@
1
+ $(document).ready ->
2
+ context = {}
3
+ active = null
4
+ dialog = $('div#browse-everything')
5
+
6
+ initialize = (obj,options) ->
7
+ if dialog.length == 0
8
+ dialog = $('<div id="browse-everything" class="ev-browser modal hide fade"></div>').appendTo('body')
9
+ dialog.modal({ backdrop: 'static', show: false });
10
+ context[obj] =
11
+ opts: $.extend(true, {}, options)
12
+ callbacks:
13
+ done: $.Callbacks()
14
+ cancel: $.Callbacks()
15
+ fail: $.Callbacks()
16
+ ctx = context[obj]
17
+ ctx.callback_proxy =
18
+ done: (func) -> ctx.callbacks.done.add(func) ; return this
19
+ cancel: (func) -> ctx.callbacks.cancel.add(func) ; return this
20
+ fail: (func) -> ctx.callbacks.fail.add(func) ; return this
21
+ ctx
22
+
23
+ toHiddenFields = (data) ->
24
+ fields = $.param(data)
25
+ .split('&')
26
+ .map (t) -> t.split('=',2)
27
+ elements = $(fields).map () ->
28
+ "<input type='hidden' name='#{decodeURIComponent(this[0])}' value='#{decodeURIComponent(this[1])}'/>"
29
+ $(elements.toArray().join("\n"))
30
+
31
+ $.fn.browseEverything = (options) ->
32
+ if options?
33
+ initialize(this[0], options)
34
+ $(this).click () ->
35
+ active = context[this]
36
+ dialog.load active.opts.route, () -> dialog.modal('show')
37
+ else
38
+ context[this[0]].callback_proxy
39
+
40
+ triggers = $('*[data-toggle=browse-everything]')
41
+ triggers.each () -> $(this).browseEverything($(this).data())
42
+
43
+ $(document).on 'click', 'button.ev-cancel', (event) ->
44
+ event.preventDefault()
45
+ active.callbacks.cancel.fire()
46
+ $('.ev-browser').modal('hide')
47
+
48
+ $(document).on 'click', 'button.ev-submit', (event) ->
49
+ event.preventDefault()
50
+ $(this).button('loading')
51
+ $('body').css('cursor','wait')
52
+ main_form = $(this).closest('form')
53
+ resolver_url = main_form.data('resolver')
54
+ $.ajax resolver_url,
55
+ type: 'POST'
56
+ dataType: 'json'
57
+ data: main_form.serialize()
58
+ .done (data) ->
59
+ if active.opts.target?
60
+ fields = toHiddenFields({selected_files: data})
61
+ $(active.opts.target).append($(fields))
62
+ active.callbacks.done.fire(data)
63
+ .fail (xhr,status,error) ->
64
+ active.callbacks.fail.fire(status, error, xhr.responseText)
65
+ .always ->
66
+ $('body').css('cursor','default')
67
+ $('.ev-browser').modal('hide')
68
+
69
+ $(document).on 'click', '.ev-container a', (event) ->
70
+ event.preventDefault()
71
+ $('body').css('cursor','wait')
72
+ $.ajax($(this).attr('href'))
73
+ .done (data) ->
74
+ $('.ev-files').html(data)
75
+ $('input.ev-url').each () ->
76
+ $("*[data-ev-location='#{$(this).val()}']").addClass('ev-selected')
77
+ .fail (xhr,status,error) ->
78
+ $('.ev-files').html(xhr.responseText)
79
+ .always ->
80
+ $('body').css('cursor','default')
81
+
82
+ $(document).on 'click', '.ev-providers a', (event) ->
83
+ $('.ev-providers li').removeClass('ev-selected')
84
+ $(this).closest('li').addClass('ev-selected')
85
+
86
+ $(document).on 'click', '.ev-file a', (event) ->
87
+ event.preventDefault()
88
+ target = $(this).closest('*[data-ev-location]')
89
+ target_form = $('form.ev-submit-form')
90
+ file_location = target.data('ev-location')
91
+ target.toggleClass('ev-selected')
92
+ if target.hasClass('ev-selected')
93
+ hidden_input = $("<input type='hidden' class='ev-url' name='selected_files[]' value='#{file_location}'>")
94
+ target_form.append(hidden_input)
95
+ else
96
+ $("form.ev-submit-form input[value='#{file_location}']").remove()
97
+
98
+ count = $('input.ev-url').length
99
+ files = if count == 1 then "file" else "files"
100
+ $('.ev-status').html("#{count} #{files} selected")
101
+
102
+ $(document).on 'click', '.ev-auth', (event) ->
103
+ event.preventDefault()
104
+ auth_win = window.open($(this).attr('href'))
105
+ check_func = ->
106
+ if auth_win.closed
107
+ $('.ev-providers .ev-selected a').click()
108
+ else
109
+ window.setTimeout check_func, 1000
110
+ check_func()