browse-everything 0.12.0 → 0.13.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.
- checksums.yaml +4 -4
 - data/.engine_cart.yml +1 -0
 - data/.rubocop.yml +6 -0
 - data/.rubocop_todo.yml +8 -32
 - data/README.md +2 -1
 - data/app/assets/javascripts/browse_everything/behavior.js.coffee +20 -10
 - data/app/assets/stylesheets/browse_everything/_browse_everything.scss +15 -16
 - data/app/controllers/browse_everything_controller.rb +29 -29
 - data/app/views/browse_everything/_files.html.erb +0 -5
 - data/app/views/browse_everything/index.html.erb +3 -0
 - data/browse-everything.gemspec +1 -1
 - data/lib/browse_everything/browser.rb +1 -1
 - data/lib/browse_everything/driver/base.rb +8 -8
 - data/lib/browse_everything/driver/box.rb +81 -72
 - data/lib/browse_everything/driver/dropbox.rb +35 -29
 - data/lib/browse_everything/driver/file_system.rb +50 -30
 - data/lib/browse_everything/driver/google_drive.rb +15 -15
 - data/lib/browse_everything/driver/s3.rb +82 -27
 - data/lib/browse_everything/driver/sky_drive.rb +17 -17
 - data/lib/browse_everything/version.rb +1 -1
 - data/lib/generators/browse_everything/templates/browse_everything_providers.yml.example +5 -4
 - data/spec/fixtures/vcr_cassettes/box.yml +498 -0
 - data/spec/unit/box_spec.rb +168 -0
 - data/spec/unit/s3_spec.rb +62 -5
 - metadata +10 -5
 
| 
         @@ -3,39 +3,45 @@ require 'dropbox_sdk' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module BrowseEverything
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Driver
         
     | 
| 
       5 
5 
     | 
    
         
             
                class Dropbox < Base
         
     | 
| 
      
 6 
     | 
    
         
            +
                  CONFIG_KEYS = [:app_key, :app_secret].freeze
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
       6 
8 
     | 
    
         
             
                  def icon
         
     | 
| 
       7 
9 
     | 
    
         
             
                    'dropbox'
         
     | 
| 
       8 
10 
     | 
    
         
             
                  end
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
12 
     | 
    
         
             
                  def validate_config
         
     | 
| 
       11 
     | 
    
         
            -
                     
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                    end
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return if CONFIG_KEYS.all? { |key| config[key].present? }
         
     | 
| 
      
 14 
     | 
    
         
            +
                    raise BrowseEverything::InitializationError, "Dropbox driver requires #{CONFIG_KEYS.inspect}"
         
     | 
| 
       14 
15 
     | 
    
         
             
                  end
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
      
 17 
     | 
    
         
            +
                  # @return [Array<BrowseEverything::FileEntry>]
         
     | 
| 
       16 
18 
     | 
    
         
             
                  def contents(path = '')
         
     | 
| 
       17 
     | 
    
         
            -
                    path.sub!(/^[\/.] 
     | 
| 
       18 
     | 
    
         
            -
                    result =  
     | 
| 
       19 
     | 
    
         
            -
                     
     | 
| 
       20 
     | 
    
         
            -
                      result << BrowseEverything::FileEntry.new(
         
     | 
| 
       21 
     | 
    
         
            -
                        Pathname(path).join('..'),
         
     | 
| 
       22 
     | 
    
         
            -
                        '', '..', 0, Time.now, true
         
     | 
| 
       23 
     | 
    
         
            -
                      )
         
     | 
| 
       24 
     | 
    
         
            -
                    end
         
     | 
| 
       25 
     | 
    
         
            -
                    result += client.metadata(path)['contents'].collect do |info|
         
     | 
| 
       26 
     | 
    
         
            -
                      path = info['path']
         
     | 
| 
       27 
     | 
    
         
            -
                      BrowseEverything::FileEntry.new(
         
     | 
| 
       28 
     | 
    
         
            -
                        path,
         
     | 
| 
       29 
     | 
    
         
            -
                        [key, path].join(':'),
         
     | 
| 
       30 
     | 
    
         
            -
                        File.basename(path),
         
     | 
| 
       31 
     | 
    
         
            -
                        info['bytes'],
         
     | 
| 
       32 
     | 
    
         
            -
                        Time.parse(info['modified']),
         
     | 
| 
       33 
     | 
    
         
            -
                        info['is_dir']
         
     | 
| 
       34 
     | 
    
         
            -
                      )
         
     | 
| 
       35 
     | 
    
         
            -
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                    path.sub!(%r{ /^[\/.]+/}, '')
         
     | 
| 
      
 20 
     | 
    
         
            +
                    result = add_directory_entry(path)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    result += client.metadata(path)['contents'].collect { |info| make_file_entry(info) }
         
     | 
| 
       36 
22 
     | 
    
         
             
                    result
         
     | 
| 
       37 
23 
     | 
    
         
             
                  end
         
     | 
| 
       38 
24 
     | 
    
         | 
| 
      
 25 
     | 
    
         
            +
                  def add_directory_entry(path)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    return [] if path.empty?
         
     | 
| 
      
 27 
     | 
    
         
            +
                    [BrowseEverything::FileEntry.new(
         
     | 
| 
      
 28 
     | 
    
         
            +
                      Pathname(path).join('..'),
         
     | 
| 
      
 29 
     | 
    
         
            +
                      '', '..', 0, Time.zone.now, true
         
     | 
| 
      
 30 
     | 
    
         
            +
                    )]
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def make_file_entry(info)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    path = info['path']
         
     | 
| 
      
 35 
     | 
    
         
            +
                    BrowseEverything::FileEntry.new(
         
     | 
| 
      
 36 
     | 
    
         
            +
                      path,
         
     | 
| 
      
 37 
     | 
    
         
            +
                      [key, path].join(':'),
         
     | 
| 
      
 38 
     | 
    
         
            +
                      File.basename(path),
         
     | 
| 
      
 39 
     | 
    
         
            +
                      info['bytes'],
         
     | 
| 
      
 40 
     | 
    
         
            +
                      Time.zone.parse(info['modified']),
         
     | 
| 
      
 41 
     | 
    
         
            +
                      info['is_dir']
         
     | 
| 
      
 42 
     | 
    
         
            +
                    )
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
       39 
45 
     | 
    
         
             
                  def link_for(path)
         
     | 
| 
       40 
46 
     | 
    
         
             
                    [client.media(path)['url'], { expires: 4.hours.from_now, file_name: File.basename(path), file_size: client.metadata(path)['bytes'].to_i }]
         
     | 
| 
       41 
47 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -60,14 +66,14 @@ module BrowseEverything 
     | 
|
| 
       60 
66 
     | 
    
         | 
| 
       61 
67 
     | 
    
         
             
                  private
         
     | 
| 
       62 
68 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 69 
     | 
    
         
            +
                    def auth_flow
         
     | 
| 
      
 70 
     | 
    
         
            +
                      @csrf ||= {}
         
     | 
| 
      
 71 
     | 
    
         
            +
                      DropboxOAuth2Flow.new(config[:app_key], config[:app_secret], callback.to_s, @csrf, 'token')
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
       67 
73 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
                    def client
         
     | 
| 
      
 75 
     | 
    
         
            +
                      DropboxClient.new(token)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
       71 
77 
     | 
    
         
             
                end
         
     | 
| 
       72 
78 
     | 
    
         
             
              end
         
     | 
| 
       73 
79 
     | 
    
         
             
            end
         
     | 
| 
         @@ -6,54 +6,74 @@ module BrowseEverything 
     | 
|
| 
       6 
6 
     | 
    
         
             
                  end
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                  def validate_config
         
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                    end
         
     | 
| 
      
 9 
     | 
    
         
            +
                    return if config[:home].present?
         
     | 
| 
      
 10 
     | 
    
         
            +
                    raise BrowseEverything::InitializationError, 'FileSystem driver requires a :home argument'
         
     | 
| 
       12 
11 
     | 
    
         
             
                  end
         
     | 
| 
       13 
12 
     | 
    
         | 
| 
       14 
13 
     | 
    
         
             
                  def contents(path = '')
         
     | 
| 
       15 
14 
     | 
    
         
             
                    relative_path = path.sub(%r{^[\/.]+}, '')
         
     | 
| 
       16 
15 
     | 
    
         
             
                    real_path = File.join(config[:home], relative_path)
         
     | 
| 
       17 
     | 
    
         
            -
                     
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                     
     | 
| 
       24 
     | 
    
         
            -
                      result += [details(real_path)]
         
     | 
| 
       25 
     | 
    
         
            -
                    end
         
     | 
| 
       26 
     | 
    
         
            -
                    result.sort do |a, b|
         
     | 
| 
       27 
     | 
    
         
            -
                      if b.container?
         
     | 
| 
       28 
     | 
    
         
            -
                        a.container? ? a.name.downcase <=> b.name.downcase : 1
         
     | 
| 
       29 
     | 
    
         
            -
                      else
         
     | 
| 
       30 
     | 
    
         
            -
                        a.container? ? -1 : a.name.downcase <=> b.name.downcase
         
     | 
| 
       31 
     | 
    
         
            -
                      end
         
     | 
| 
       32 
     | 
    
         
            -
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                    entries = if File.directory?(real_path)
         
     | 
| 
      
 17 
     | 
    
         
            +
                                make_directory_entry(relative_path, real_path)
         
     | 
| 
      
 18 
     | 
    
         
            +
                              else
         
     | 
| 
      
 19 
     | 
    
         
            +
                                [details(real_path)]
         
     | 
| 
      
 20 
     | 
    
         
            +
                              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    sort_entries(entries)
         
     | 
| 
       33 
23 
     | 
    
         
             
                  end
         
     | 
| 
       34 
24 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
                  def  
     | 
| 
      
 25 
     | 
    
         
            +
                  def link_for(path)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    full_path = File.expand_path(path)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    file_size = file_size(full_path)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    ["file://#{full_path}", { file_name: File.basename(path), file_size: file_size }]
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def authorized?
         
     | 
| 
      
 32 
     | 
    
         
            +
                    true
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def details(path, display = File.basename(path))
         
     | 
| 
       36 
36 
     | 
    
         
             
                    return nil unless File.exist?(path)
         
     | 
| 
       37 
37 
     | 
    
         
             
                    info = File::Stat.new(path)
         
     | 
| 
       38 
38 
     | 
    
         
             
                    BrowseEverything::FileEntry.new(
         
     | 
| 
       39 
     | 
    
         
            -
                       
     | 
| 
      
 39 
     | 
    
         
            +
                      make_pathname(path),
         
     | 
| 
       40 
40 
     | 
    
         
             
                      [key, path].join(':'),
         
     | 
| 
       41 
     | 
    
         
            -
                      display 
     | 
| 
      
 41 
     | 
    
         
            +
                      display,
         
     | 
| 
       42 
42 
     | 
    
         
             
                      info.size,
         
     | 
| 
       43 
43 
     | 
    
         
             
                      info.mtime,
         
     | 
| 
       44 
44 
     | 
    
         
             
                      info.directory?
         
     | 
| 
       45 
45 
     | 
    
         
             
                    )
         
     | 
| 
       46 
46 
     | 
    
         
             
                  end
         
     | 
| 
       47 
47 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
                   
     | 
| 
       49 
     | 
    
         
            -
                    full_path = File.expand_path(path)
         
     | 
| 
       50 
     | 
    
         
            -
                    file_size = File.size(full_path).to_i rescue 0
         
     | 
| 
       51 
     | 
    
         
            -
                    ["file://#{full_path}", { file_name: File.basename(path), file_size: file_size }]
         
     | 
| 
       52 
     | 
    
         
            -
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  private
         
     | 
| 
       53 
49 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def make_directory_entry(relative_path, real_path)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      entries = []
         
     | 
| 
      
 52 
     | 
    
         
            +
                      if relative_path.present?
         
     | 
| 
      
 53 
     | 
    
         
            +
                        entries << details(File.expand_path('..', real_path), '..')
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
                      entries + Dir[File.join(real_path, '*')].collect { |f| details(f) }
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                    def sort_entries(entries)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      entries.sort do |a, b|
         
     | 
| 
      
 60 
     | 
    
         
            +
                        if b.container?
         
     | 
| 
      
 61 
     | 
    
         
            +
                          a.container? ? a.name.downcase <=> b.name.downcase : 1
         
     | 
| 
      
 62 
     | 
    
         
            +
                        else
         
     | 
| 
      
 63 
     | 
    
         
            +
                          a.container? ? -1 : a.name.downcase <=> b.name.downcase
         
     | 
| 
      
 64 
     | 
    
         
            +
                        end
         
     | 
| 
      
 65 
     | 
    
         
            +
                      end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    def make_pathname(path)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      Pathname.new(File.expand_path(path)).relative_path_from(Pathname.new(config[:home]))
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    def file_size(path)
         
     | 
| 
      
 73 
     | 
    
         
            +
                      File.size(path).to_i
         
     | 
| 
      
 74 
     | 
    
         
            +
                    rescue
         
     | 
| 
      
 75 
     | 
    
         
            +
                      0
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
       57 
77 
     | 
    
         
             
                end
         
     | 
| 
       58 
78 
     | 
    
         
             
              end
         
     | 
| 
       59 
79 
     | 
    
         
             
            end
         
     | 
| 
         @@ -85,22 +85,22 @@ module BrowseEverything 
     | 
|
| 
       85 
85 
     | 
    
         | 
| 
       86 
86 
     | 
    
         
             
                  private
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
      
 88 
     | 
    
         
            +
                    def authorization
         
     | 
| 
      
 89 
     | 
    
         
            +
                      return @auth_client unless @auth_client.nil?
         
     | 
| 
      
 90 
     | 
    
         
            +
                      return nil unless token.present?
         
     | 
| 
      
 91 
     | 
    
         
            +
                      auth_client.update_token!(token)
         
     | 
| 
      
 92 
     | 
    
         
            +
                      self.token = auth_client.fetch_access_token! if auth_client.expired?
         
     | 
| 
      
 93 
     | 
    
         
            +
                      auth_client
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
       95 
95 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
      
 96 
     | 
    
         
            +
                    def auth_client
         
     | 
| 
      
 97 
     | 
    
         
            +
                      @auth_client ||= Signet::OAuth2::Client.new token_credential_uri: 'https://www.googleapis.com/oauth2/v3/token',
         
     | 
| 
      
 98 
     | 
    
         
            +
                                                                  authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
         
     | 
| 
      
 99 
     | 
    
         
            +
                                                                  scope: 'https://www.googleapis.com/auth/drive',
         
     | 
| 
      
 100 
     | 
    
         
            +
                                                                  client_id: config[:client_id],
         
     | 
| 
      
 101 
     | 
    
         
            +
                                                                  client_secret: config[:client_secret],
         
     | 
| 
      
 102 
     | 
    
         
            +
                                                                  redirect_uri: callback
         
     | 
| 
      
 103 
     | 
    
         
            +
                    end
         
     | 
| 
       104 
104 
     | 
    
         
             
                end
         
     | 
| 
       105 
105 
     | 
    
         
             
              end
         
     | 
| 
       106 
106 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,10 +3,17 @@ require 'aws-sdk' 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module BrowseEverything
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Driver
         
     | 
| 
       5 
5 
     | 
    
         
             
                class S3 < Base
         
     | 
| 
       6 
     | 
    
         
            -
                  DEFAULTS = {  
     | 
| 
       7 
     | 
    
         
            -
                   
     | 
| 
      
 6 
     | 
    
         
            +
                  DEFAULTS = { response_type: :signed_url }.freeze
         
     | 
| 
      
 7 
     | 
    
         
            +
                  RESPONSE_TYPES = [:signed_url, :public_url, :s3_uri].freeze
         
     | 
| 
      
 8 
     | 
    
         
            +
                  CONFIG_KEYS = [:bucket].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  attr_reader :entries
         
     | 
| 
       8 
11 
     | 
    
         | 
| 
       9 
12 
     | 
    
         
             
                  def initialize(config, *args)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    if config.key?(:signed_url) && config.delete(:signed_url) == false
         
     | 
| 
      
 14 
     | 
    
         
            +
                      warn '[DEPRECATION] Amazon S3 driver: `:signed_url` is deprecated.  Please use `:response_type` instead.'
         
     | 
| 
      
 15 
     | 
    
         
            +
                      config[:response_type] = :public_url
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
       10 
17 
     | 
    
         
             
                    config = DEFAULTS.merge(config)
         
     | 
| 
       11 
18 
     | 
    
         
             
                    super
         
     | 
| 
       12 
19 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -16,27 +23,48 @@ module BrowseEverything 
     | 
|
| 
       16 
23 
     | 
    
         
             
                  end
         
     | 
| 
       17 
24 
     | 
    
         | 
| 
       18 
25 
     | 
    
         
             
                  def validate_config
         
     | 
| 
      
 26 
     | 
    
         
            +
                    if config.values_at(:app_key, :app_secret).compact.length == 1
         
     | 
| 
      
 27 
     | 
    
         
            +
                      raise BrowseEverything::InitializationError, 'Amazon S3 driver: If either :app_key or :app_secret is provided, both must be.'
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                    unless RESPONSE_TYPES.include?(config[:response_type].to_sym)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      raise BrowseEverything::InitializationError, "Amazon S3 driver: Valid response types: #{RESPONSE_TYPES.join(',')}"
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
       19 
32 
     | 
    
         
             
                    return if CONFIG_KEYS.all? { |key| config[key].present? }
         
     | 
| 
       20 
33 
     | 
    
         
             
                    raise BrowseEverything::InitializationError, "Amazon S3 driver requires #{CONFIG_KEYS.join(',')}"
         
     | 
| 
       21 
34 
     | 
    
         
             
                  end
         
     | 
| 
       22 
35 
     | 
    
         | 
| 
      
 36 
     | 
    
         
            +
                  # @return [Array<BrowseEverything::FileEntry>]
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # Appends / to the path before querying S3
         
     | 
| 
       23 
38 
     | 
    
         
             
                  def contents(path = '')
         
     | 
| 
       24 
39 
     | 
    
         
             
                    path = File.join(path, '') unless path.empty?
         
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
       26 
     | 
    
         
            -
                     
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                     
     | 
| 
      
 40 
     | 
    
         
            +
                    init_entries(path)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    generate_listing(path)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    sort_entries
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def generate_listing(path)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    listing = client.list_objects(bucket: config[:bucket], delimiter: '/', prefix: full_path(path))
         
     | 
| 
      
 47 
     | 
    
         
            +
                    add_directories(listing)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    add_files(listing, path)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def add_directories(listing)
         
     | 
| 
       33 
52 
     | 
    
         
             
                    listing.common_prefixes.each do |prefix|
         
     | 
| 
       34 
     | 
    
         
            -
                       
     | 
| 
      
 53 
     | 
    
         
            +
                      entries << entry_for(from_base(prefix.prefix), 0, Time.current, true)
         
     | 
| 
       35 
54 
     | 
    
         
             
                    end
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  def add_files(listing, path)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    listing.contents.each do |entry|
         
     | 
| 
      
 59 
     | 
    
         
            +
                      key = from_base(entry.key)
         
     | 
| 
      
 60 
     | 
    
         
            +
                      unless strip(key) == strip(path)
         
     | 
| 
      
 61 
     | 
    
         
            +
                        entries << entry_for(key, entry.size, entry.last_modified, false)
         
     | 
| 
      
 62 
     | 
    
         
            +
                      end
         
     | 
| 
       38 
63 
     | 
    
         
             
                    end
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                  def sort_entries
         
     | 
| 
      
 67 
     | 
    
         
            +
                    entries.sort do |a, b|
         
     | 
| 
       40 
68 
     | 
    
         
             
                      if b.container?
         
     | 
| 
       41 
69 
     | 
    
         
             
                        a.container? ? a.name.downcase <=> b.name.downcase : 1
         
     | 
| 
       42 
70 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -45,28 +73,34 @@ module BrowseEverything 
     | 
|
| 
       45 
73 
     | 
    
         
             
                    end
         
     | 
| 
       46 
74 
     | 
    
         
             
                  end
         
     | 
| 
       47 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                  def init_entries(path)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    @entries = if path.empty?
         
     | 
| 
      
 78 
     | 
    
         
            +
                                 []
         
     | 
| 
      
 79 
     | 
    
         
            +
                               else
         
     | 
| 
      
 80 
     | 
    
         
            +
                                 [BrowseEverything::FileEntry.new(Pathname(path).join('..').to_s, '', '..',
         
     | 
| 
      
 81 
     | 
    
         
            +
                                                                  0, Time.current, true)]
         
     | 
| 
      
 82 
     | 
    
         
            +
                               end
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
       48 
85 
     | 
    
         
             
                  def entry_for(name, size, date, dir)
         
     | 
| 
       49 
86 
     | 
    
         
             
                    BrowseEverything::FileEntry.new(name, [key, name].join(':'), File.basename(name), size, date, dir)
         
     | 
| 
       50 
87 
     | 
    
         
             
                  end
         
     | 
| 
       51 
88 
     | 
    
         | 
| 
       52 
89 
     | 
    
         
             
                  def details(path)
         
     | 
| 
       53 
     | 
    
         
            -
                    entry = client.head_object(path)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    entry = client.head_object(full_path(path))
         
     | 
| 
       54 
91 
     | 
    
         
             
                    BrowseEverything::FileEntry.new(
         
     | 
| 
       55 
     | 
    
         
            -
                      entry.key,
         
     | 
| 
       56 
     | 
    
         
            -
                       
     | 
| 
       57 
     | 
    
         
            -
                       
     | 
| 
       58 
     | 
    
         
            -
                      entry.size,
         
     | 
| 
       59 
     | 
    
         
            -
                      entry.last_modified,
         
     | 
| 
       60 
     | 
    
         
            -
                      false
         
     | 
| 
      
 92 
     | 
    
         
            +
                      entry.key, [key, entry.key].join(':'),
         
     | 
| 
      
 93 
     | 
    
         
            +
                      File.basename(entry.key), entry.size,
         
     | 
| 
      
 94 
     | 
    
         
            +
                      entry.last_modified, false
         
     | 
| 
       61 
95 
     | 
    
         
             
                    )
         
     | 
| 
       62 
96 
     | 
    
         
             
                  end
         
     | 
| 
       63 
97 
     | 
    
         | 
| 
       64 
98 
     | 
    
         
             
                  def link_for(path)
         
     | 
| 
       65 
     | 
    
         
            -
                    obj = bucket.object(path)
         
     | 
| 
       66 
     | 
    
         
            -
                     
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                     
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
      
 99 
     | 
    
         
            +
                    obj = bucket.object(full_path(path))
         
     | 
| 
      
 100 
     | 
    
         
            +
                    case config[:response_type].to_sym
         
     | 
| 
      
 101 
     | 
    
         
            +
                    when :signed_url then obj.presigned_url(:get, expires_in: 14400)
         
     | 
| 
      
 102 
     | 
    
         
            +
                    when :public_url then obj.public_url
         
     | 
| 
      
 103 
     | 
    
         
            +
                    when :s3_uri     then "s3://#{obj.bucket_name}/#{obj.key}"
         
     | 
| 
       70 
104 
     | 
    
         
             
                    end
         
     | 
| 
       71 
105 
     | 
    
         
             
                  end
         
     | 
| 
       72 
106 
     | 
    
         | 
| 
         @@ -79,8 +113,29 @@ module BrowseEverything 
     | 
|
| 
       79 
113 
     | 
    
         
             
                  end
         
     | 
| 
       80 
114 
     | 
    
         | 
| 
       81 
115 
     | 
    
         
             
                  def client
         
     | 
| 
       82 
     | 
    
         
            -
                    @client ||= Aws::S3::Client.new( 
     | 
| 
      
 116 
     | 
    
         
            +
                    @client ||= Aws::S3::Client.new(aws_config)
         
     | 
| 
       83 
117 
     | 
    
         
             
                  end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                  private
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    def strip(path)
         
     | 
| 
      
 122 
     | 
    
         
            +
                      path.sub %r{^/?(.+?)/?$}, '\1'
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    def from_base(key)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      Pathname.new(key).relative_path_from(Pathname.new(config[:base].to_s)).to_s
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                    def full_path(path)
         
     | 
| 
      
 130 
     | 
    
         
            +
                      config[:base].present? ? File.join(config[:base], path) : path
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                    def aws_config
         
     | 
| 
      
 134 
     | 
    
         
            +
                      result = {}
         
     | 
| 
      
 135 
     | 
    
         
            +
                      result[:credentials] = Aws::Credentials.new(config[:app_key], config[:app_secret]) if config[:app_key].present?
         
     | 
| 
      
 136 
     | 
    
         
            +
                      result[:region] = config[:region] if config.key?(:region)
         
     | 
| 
      
 137 
     | 
    
         
            +
                      result
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
       84 
139 
     | 
    
         
             
                end
         
     | 
| 
       85 
140 
     | 
    
         
             
              end
         
     | 
| 
       86 
141 
     | 
    
         
             
            end
         
     | 
| 
         @@ -100,26 +100,26 @@ module BrowseEverything 
     | 
|
| 
       100 
100 
     | 
    
         | 
| 
       101 
101 
     | 
    
         
             
                  private
         
     | 
| 
       102 
102 
     | 
    
         | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
      
 103 
     | 
    
         
            +
                    def oauth_client
         
     | 
| 
      
 104 
     | 
    
         
            +
                      Skydrive::Oauth::Client.new(config[:client_id], config[:client_secret], callback.to_s, 'wl.skydrive')
         
     | 
| 
      
 105 
     | 
    
         
            +
                      # TODO: error checking here
         
     | 
| 
      
 106 
     | 
    
         
            +
                    end
         
     | 
| 
       107 
107 
     | 
    
         | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
      
 108 
     | 
    
         
            +
                    def rehydrate_token
         
     | 
| 
      
 109 
     | 
    
         
            +
                      return @rehydrate_token if @rehydrate_token
         
     | 
| 
      
 110 
     | 
    
         
            +
                      token_str = @token[:token]
         
     | 
| 
      
 111 
     | 
    
         
            +
                      token_expires = @token[:expires_at]
         
     | 
| 
      
 112 
     | 
    
         
            +
                      Rails.logger.warn "\n\n Rehydrating: #{@token} #{token_str} #{token_expires}"
         
     | 
| 
      
 113 
     | 
    
         
            +
                      @rehydrate_token = oauth_client.get_access_token_from_hash(token_str, expires_at: token_expires)
         
     | 
| 
      
 114 
     | 
    
         
            +
                    end
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
      
 116 
     | 
    
         
            +
                    def safe_id(id)
         
     | 
| 
      
 117 
     | 
    
         
            +
                      id.tr('.', '-')
         
     | 
| 
      
 118 
     | 
    
         
            +
                    end
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
      
 120 
     | 
    
         
            +
                    def real_id(id)
         
     | 
| 
      
 121 
     | 
    
         
            +
                      id.tr('-', '.')
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
       123 
123 
     | 
    
         
             
                end
         
     | 
| 
       124 
124 
     | 
    
         
             
              end
         
     | 
| 
       125 
125 
     | 
    
         
             
            end
         
     | 
| 
         @@ -12,11 +12,12 @@ 
     | 
|
| 
       12 
12 
     | 
    
         
             
            #   :client_id: YOUR_GOOGLE_API_CLIENT_ID
         
     | 
| 
       13 
13 
     | 
    
         
             
            #   :client_secret: YOUR_GOOGLE_API_CLIENT_SECRET
         
     | 
| 
       14 
14 
     | 
    
         
             
            # s3:
         
     | 
| 
       15 
     | 
    
         
            -
            #   :app_key: YOUR_AWS_S3_KEY
         
     | 
| 
       16 
     | 
    
         
            -
            #   :app_secret: YOUR_AWS_S3_SECRET
         
     | 
| 
       17 
15 
     | 
    
         
             
            #   :bucket: YOUR_AWS_S3_BUCKET
         
     | 
| 
       18 
     | 
    
         
            -
            #   : 
     | 
| 
       19 
     | 
    
         
            -
            #   : 
     | 
| 
      
 16 
     | 
    
         
            +
            #   :response_type: :signed_url # set to :public_url for public urls or :s3_uri for an s3://BUCKET/KEY uri
         
     | 
| 
      
 17 
     | 
    
         
            +
            #   :app_key: YOUR_AWS_S3_KEY       # :app_key, :app_secret, and :region can be specified
         
     | 
| 
      
 18 
     | 
    
         
            +
            #   :app_secret: YOUR_AWS_S3_SECRET # explicitly here, or left out to use system-configured
         
     | 
| 
      
 19 
     | 
    
         
            +
            #   :region: YOUR_AWS_S3_REGION     # defaults.
         
     | 
| 
      
 20 
     | 
    
         
            +
            #   See https://aws.amazon.com/blogs/security/a-new-and-standardized-way-to-manage-credentials-in-the-aws-sdks/
         
     | 
| 
       20 
21 
     | 
    
         
             
            # sky_drive:
         
     | 
| 
       21 
22 
     | 
    
         
             
            #   :client_id: YOUR_MS_LIVE_CONNECT_CLIENT_ID
         
     | 
| 
       22 
23 
     | 
    
         
             
            #   :client_secret: YOUR_MS_LIVE_CONNECT_CLIENT_SECRET
         
     |