browse-everything 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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()