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
@@ -0,0 +1,90 @@
1
+ module BrowseEverything
2
+ module Driver
3
+ class Box < Base
4
+ require 'ruby-box'
5
+
6
+ def icon
7
+ 'cloud'
8
+ end
9
+
10
+ def validate_config
11
+ unless config[:client_id]
12
+ raise BrowseEverything::InitializationError, "Box driver requires a :client_id argument"
13
+ end
14
+ unless config[:client_secret]
15
+ raise BrowseEverything::InitializationError, "Box driver requires a :client_secret argument"
16
+ end
17
+ end
18
+
19
+ def contents(path='')
20
+ path.sub!(/^[\/.]+/,'')
21
+ result = []
22
+ unless path.empty?
23
+ result << BrowseEverything::FileEntry.new(
24
+ Pathname(path).join('..'),
25
+ '', '..', 0, Time.now, true
26
+ )
27
+ end
28
+ folder = path.empty? ? box_client.root_folder : box_client.folder(path)
29
+ result += folder.items.collect do |f|
30
+ BrowseEverything::FileEntry.new(
31
+ File.join(path,f.name),#id here
32
+ "#{self.key}:#{File.join(path,f.name)}",#single use link
33
+ f.name,
34
+ f.size,
35
+ f.created_at,
36
+ f.type == 'folder'
37
+ )
38
+ end
39
+ result
40
+ end
41
+
42
+ def link_for(path)
43
+ file = box_client.file(path)
44
+ file.create_shared_link
45
+ link = file.shared_link
46
+ extras = link.unshared_at.nil? ? {} : { expires: link.unshared_at }
47
+ [link.download_url,extras]
48
+ end
49
+
50
+ def details(f)
51
+ end
52
+
53
+ def auth_link
54
+ callback = connector_response_url(config[:url_options])
55
+ oauth_client.authorize_url(callback.to_s)
56
+ end
57
+
58
+ def authorized?
59
+ #false
60
+ @token.present?
61
+ end
62
+
63
+ def connect(params,data)
64
+ @token = oauth_client.get_access_token(params[:code]).token
65
+ end
66
+
67
+ private
68
+ def oauth_client
69
+ session = RubyBox::Session.new({
70
+ client_id: config[:client_id],
71
+ client_secret: config[:client_secret]
72
+ })
73
+
74
+ session
75
+ #todo error checking here
76
+ end
77
+
78
+ def box_client
79
+ session = RubyBox::Session.new({
80
+ client_id: config[:client_id],
81
+ client_secret: config[:client_secret],
82
+ access_token: @token
83
+ })
84
+ RubyBox::Client.new(session)
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,74 @@
1
+ require 'dropbox_sdk'
2
+
3
+ module BrowseEverything
4
+ module Driver
5
+ class DropBox < Base
6
+
7
+ def icon
8
+ 'dropbox'
9
+ end
10
+
11
+ def validate_config
12
+ unless [:app_key,:app_secret].all? { |key| config[key].present? }
13
+ raise BrowseEverything::InitializationError, "DropBox driver requires :app_key and :app_secret"
14
+ end
15
+ end
16
+
17
+ def contents(path='')
18
+ path.sub!(/^[\/.]+/,'')
19
+ result = []
20
+ unless path.empty?
21
+ result << BrowseEverything::FileEntry.new(
22
+ Pathname(path).join('..'),
23
+ '', '..', 0, Time.now, true
24
+ )
25
+ end
26
+ result += client.metadata(path)['contents'].collect do |info|
27
+ path = info['path']
28
+ BrowseEverything::FileEntry.new(
29
+ path,
30
+ [self.key,path].join(':'),
31
+ File.basename(path),
32
+ info['size'],
33
+ Time.parse(info['modified']),
34
+ info['is_dir']
35
+ )
36
+ end
37
+ result
38
+ end
39
+
40
+ def link_for(path)
41
+ [client.media(path)['url'], { expires: 4.hours.from_now }]
42
+ end
43
+
44
+ def details(path)
45
+ contents(path).first
46
+ end
47
+
48
+ def auth_link
49
+ [ auth_flow.start('drop_box'), @csrf ]
50
+ end
51
+
52
+ def connect(params,data)
53
+ @csrf = data
54
+ @token, user, state = auth_flow.finish(params)
55
+ @token
56
+ end
57
+
58
+ def authorized?
59
+ token.present?
60
+ end
61
+
62
+ private
63
+ def auth_flow
64
+ @csrf ||= {}
65
+ DropboxOAuth2Flow.new(config[:app_key], config[:app_secret], connector_response_url(config[:url_options]).to_s,@csrf,:token)
66
+ end
67
+
68
+ def client
69
+ DropboxClient.new(token)
70
+ end
71
+ end
72
+
73
+ end
74
+ end
@@ -0,0 +1,62 @@
1
+ module BrowseEverything
2
+ module Driver
3
+ class FileSystem < Base
4
+
5
+ def icon
6
+ 'file'
7
+ end
8
+
9
+ def validate_config
10
+ unless config[:home]
11
+ raise BrowseEverything::InitializationError, "FileSystem driver requires a :home argument"
12
+ end
13
+ end
14
+
15
+ def contents(path='')
16
+ relative_path = path.sub(%r{^[/.]+},'')
17
+ real_path = File.join(config[:home], relative_path)
18
+ result = []
19
+ if File.directory?(real_path)
20
+ if relative_path.present?
21
+ result << details('..')
22
+ end
23
+ result += Dir[File.join(real_path,'*')].collect { |f| details(f) }
24
+ elsif File.exists?(real_path)
25
+ result += [details(real_path)]
26
+ end
27
+ result.sort do |a,b|
28
+ if b.container?
29
+ a.container? ? a.name.downcase <=> b.name.downcase : 1
30
+ else
31
+ a.container? ? -1 : a.name.downcase <=> b.name.downcase
32
+ end
33
+ end
34
+ end
35
+
36
+ def details(path)
37
+ if File.exists?(path)
38
+ info = File::Stat.new(path)
39
+ BrowseEverything::FileEntry.new(
40
+ Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(config[:home])),
41
+ [self.key,path].join(':'),
42
+ File.basename(path),
43
+ info.size,
44
+ info.mtime,
45
+ info.directory?
46
+ )
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ def link_for(path)
53
+ "file://#{File.expand_path(path)}"
54
+ end
55
+
56
+ def authorized?
57
+ true
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,103 @@
1
+ module BrowseEverything
2
+ module Driver
3
+ class GoogleDrive < Base
4
+
5
+ require 'google/api_client'
6
+
7
+ def icon
8
+ 'google-plus-sign'
9
+ end
10
+
11
+ def validate_config
12
+ unless config[:client_id]
13
+ raise BrowseEverything::InitializationError, "GoogleDrive driver requires a :client_id argument"
14
+ end
15
+ unless config[:client_secret]
16
+ raise BrowseEverything::InitializationError, "GoogleDrive driver requires a :client_secret argument"
17
+ end
18
+ end
19
+
20
+ def contents(path='')
21
+ default_params = { }
22
+ page_token = nil
23
+ files = []
24
+ begin
25
+ unless path.blank?
26
+ default_params[:q] = "'#{path}' in parents"
27
+ end
28
+ unless page_token.blank?
29
+ default_params[:pageToken] = page_token
30
+ end
31
+ api_result = oauth_client.execute( api_method: drive.files.list, parameters: default_params )
32
+ response = JSON.parse(api_result.response.body)
33
+ page_token = response["nextPageToken"]
34
+ response["items"].select do |file|
35
+ path.blank? ? (file["parents"].blank? or file["parents"].any?{|p| p["isRoot"] }) : true
36
+ end.each do |file|
37
+ files << details(file, path)
38
+ end
39
+ end while !page_token.blank?
40
+ files.compact
41
+ end
42
+
43
+ def details(file, path='')
44
+ if file["downloadUrl"] or file["mimeType"] == "application/vnd.google-apps.folder"
45
+ BrowseEverything::FileEntry.new(
46
+ file["id"],
47
+ "#{self.key}:#{file["id"]}",
48
+ file["title"],
49
+ (file["fileSize"] || 0),
50
+ Time.parse(file["modifiedDate"]),
51
+ file["mimeType"] == "application/vnd.google-apps.folder",
52
+ file["mimeType"] == "application/vnd.google-apps.folder" ?
53
+ "directory" :
54
+ file["mimeType"]
55
+ )
56
+ end
57
+ end
58
+
59
+ def link_for(id)
60
+ api_method = drive.files.get
61
+ api_result = oauth_client.execute(api_method: api_method, parameters: {fileId: id})
62
+ download_url = JSON.parse(api_result.response.body)["downloadUrl"]
63
+ auth_header = {'Authorization' => "Bearer #{oauth_client.authorization.access_token.to_s}"}
64
+ [download_url,{ auth_header: auth_header, expires: 1.hour.from_now }]
65
+ end
66
+
67
+ def auth_link
68
+ oauth_client.authorization.authorization_uri.to_s
69
+ end
70
+
71
+ def authorized?
72
+ @token.present?
73
+ end
74
+
75
+ def connect(params, data)
76
+ oauth_client.authorization.code = params[:code]
77
+ @token = oauth_client.authorization.fetch_access_token!
78
+ end
79
+
80
+ def drive
81
+ oauth_client.discovered_api('drive', 'v2')
82
+ end
83
+
84
+ private
85
+
86
+ def oauth_client
87
+ if @client.nil?
88
+ callback = connector_response_url(config[:url_options])
89
+ @client = Google::APIClient.new
90
+ @client.authorization.client_id = config[:client_id]
91
+ @client.authorization.client_secret = config[:client_secret]
92
+ @client.authorization.scope = "https://www.googleapis.com/auth/drive"
93
+ @client.authorization.redirect_uri = callback
94
+ @client.authorization.update_token!(@token) if @token.present?
95
+ end
96
+ #todo error checking here
97
+ @client
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,132 @@
1
+ module BrowseEverything
2
+ module Driver
3
+ class SkyDrive < Base
4
+
5
+ require 'skydrive'
6
+
7
+ def icon
8
+ 'windows'
9
+ end
10
+
11
+ def container_items
12
+ ["folder","album"]
13
+ end
14
+
15
+ def validate_config
16
+ unless config[:client_id]
17
+ raise BrowseEverything::InitializationError, "SkyDrive driver requires a :client_id argument"
18
+ end
19
+ unless config[:client_secret]
20
+ raise BrowseEverything::InitializationError, "SkyDrive driver requires a :client_secret argument"
21
+ end
22
+ end
23
+
24
+ def contents(path='')
25
+ result = []
26
+ token_obj = rehydrate_token
27
+ client = Skydrive::Client.new(token_obj)
28
+ if (path == '')
29
+ folder = client.my_skydrive
30
+ #todo do some loop to get down to my path
31
+ else
32
+ folder = client.get("/#{path.gsub("-",".")}/")
33
+ result += [parent_folder_details(folder)] if folder.parent_id
34
+ end
35
+
36
+ files = folder.files
37
+ files.items.each do |item|
38
+ if container_items.include? item.type
39
+ result += [folder_details(item)]
40
+ else
41
+ Rails.logger.warn("\n\nID #{item.id} #{item.type}")
42
+ result += [file_details(item)]
43
+ end
44
+ end
45
+ result
46
+ end
47
+
48
+ def link_for(path)
49
+ response = Skydrive::Client.new(rehydrate_token).get("/#{real_id(path)}/")
50
+ [response.download_link, {expires: 1.hour.from_now}]
51
+ end
52
+
53
+
54
+
55
+ def file_details(file)
56
+ BrowseEverything::FileEntry.new(
57
+ safe_id(file.id),
58
+ "#{key}:#{safe_id(file.id)}",
59
+ file.name,
60
+ file.size,
61
+ file.updated_time,
62
+ false
63
+ )
64
+ end
65
+
66
+ def parent_folder_details(file)
67
+ BrowseEverything::FileEntry.new(
68
+ safe_id(file.parent_id),
69
+ "#{key}:#{safe_id(file.parent_id)}",
70
+ "..",
71
+ 0,
72
+ Time.now,
73
+ true
74
+ )
75
+ end
76
+
77
+
78
+
79
+
80
+ def folder_details(folder)
81
+ BrowseEverything::FileEntry.new(
82
+ safe_id(folder.id),
83
+ "#{key}:#{safe_id(folder.id)}",
84
+ folder.name,
85
+ 0,
86
+ folder.updated_time,
87
+ true,
88
+ 'directory'#todo how are we getting mime type
89
+ )
90
+ end
91
+
92
+
93
+ def auth_link
94
+ oauth_client.authorize_url
95
+ end
96
+
97
+ def authorized?
98
+ return false unless @token.present?
99
+ return !rehydrate_token.expired?
100
+ end
101
+
102
+ def connect(params,data)
103
+ Rails.logger.warn "params #{params.inspect}"
104
+ token = oauth_client.get_access_token(params[:code])
105
+ @token = {token:token.token, expires_at:token.expires_at}
106
+ end
107
+
108
+ private
109
+ def oauth_client
110
+ callback = connector_response_url(config[:url_options])
111
+ Skydrive::Oauth::Client.new(config[:client_id], config[:client_secret], callback.to_s,"wl.skydrive")
112
+ #todo error checking here
113
+ end
114
+
115
+ def rehydrate_token
116
+ return @rehydrate_token if @rehydrate_token
117
+ token_str = @token[:token]
118
+ token_expires = @token[:expires_at]
119
+ Rails.logger.warn "\n\n Rehydrating: #{@token} #{token_str} #{token_expires}"
120
+ @rehydrate_token = oauth_client.get_access_token_from_hash(token_str,{expires_at:token_expires})
121
+ end
122
+
123
+ def safe_id(id)
124
+ id.gsub(".","-")
125
+ end
126
+
127
+ def real_id(id)
128
+ id.gsub("-",".")
129
+ end
130
+ end
131
+ end
132
+ end