boxr 0.0.3 → 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.
- checksums.yaml +4 -4
- data/.env.example +6 -3
- data/Rakefile +0 -2
- data/examples/enterprise_events.rb +8 -8
- data/examples/oauth.rb +27 -0
- data/examples/user_events.rb +12 -12
- data/lib/boxr.rb +12 -11
- data/lib/boxr/auth.rb +46 -0
- data/lib/boxr/client.rb +255 -214
- data/lib/boxr/collaborations.rb +56 -56
- data/lib/boxr/comments.rb +38 -38
- data/lib/boxr/events.rb +16 -16
- data/lib/boxr/exceptions.rb +35 -35
- data/lib/boxr/files.rb +209 -209
- data/lib/boxr/folders.rb +117 -117
- data/lib/boxr/groups.rb +61 -61
- data/lib/boxr/metadata.rb +22 -22
- data/lib/boxr/search.rb +20 -20
- data/lib/boxr/shared_items.rb +8 -8
- data/lib/boxr/tasks.rb +83 -83
- data/lib/boxr/users.rb +80 -82
- data/lib/boxr/version.rb +1 -1
- data/spec/boxr_spec.rb +441 -441
- metadata +5 -4
- data/lib/tasks/oauth.rake +0 -22
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 85a9e52479cab2e593a06741ba16b2e4a44f60d6
         | 
| 4 | 
            +
              data.tar.gz: 20e2668309a30f3adbd07a0f494ccb97788144a0
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 46f24ca8c3bfb93a098c5dfbd63b69eeff3a316e662d119d096a0c92264608d755629fe933955d9ab5ad7b78d960c870ffb05bcc6427ee9bc78e1dda7568ca30
         | 
| 7 | 
            +
              data.tar.gz: 7f62b487fe1526578ab85386dda281b6cabcf1f21a69fcc83b39cd469dc7109b060dea139a4775016e2f060269045b2641bff38dfcc144478335b7939f08d274
         | 
    
        data/.env.example
    CHANGED
    
    | @@ -3,7 +3,10 @@ | |
| 3 3 | 
             
            #3. click 'Edit Application'
         | 
| 4 4 | 
             
            #4. check the boxes for 'Read and write all files and folders' and 'Manage an enterprise'
         | 
| 5 5 | 
             
            #5. click 'Create a developer token'
         | 
| 6 | 
            -
            #6. paste the  | 
| 7 | 
            -
            #7.  | 
| 6 | 
            +
            #6. copy and paste the developer token below
         | 
| 7 | 
            +
            #7. copy and paste the client id and client secret of your Box app below
         | 
| 8 | 
            +
            #8. save this file as .env
         | 
| 8 9 |  | 
| 9 | 
            -
            BOX_DEVELOPER_TOKEN= | 
| 10 | 
            +
            BOX_DEVELOPER_TOKEN={a valid developer token for your Box app}
         | 
| 11 | 
            +
            BOX_CLIENT_ID={client id of your Box app}
         | 
| 12 | 
            +
            BOX_CLIENT_SECRET={client secret of your Box app}
         | 
    
        data/Rakefile
    CHANGED
    
    
| @@ -5,17 +5,17 @@ require 'awesome_print' | |
| 5 5 | 
             
            client = Boxr::Client.new(ENV['BOX_DEVELOPER_TOKEN'])
         | 
| 6 6 |  | 
| 7 7 | 
             
            now = Time.now
         | 
| 8 | 
            -
            start_date = now - (60*60*24 | 
| 9 | 
            -
            end_date = now | 
| 8 | 
            +
            start_date = now - (60*60*24) #one day ago
         | 
| 9 | 
            +
            end_date = now
         | 
| 10 10 |  | 
| 11 11 | 
             
            stream_position = 0
         | 
| 12 12 | 
             
            puts "fetching enterprise events..."
         | 
| 13 13 | 
             
            loop do
         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 14 | 
            +
              event_response = client.enterprise_events(stream_position: stream_position, created_after: start_date.utc, created_before: end_date.utc)
         | 
| 15 | 
            +
              event_response.events.each do |event|
         | 
| 16 | 
            +
                puts "#{event.event_type}, #{event.created_by.name}"
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
              stream_position = event_response.next_stream_position
         | 
| 19 19 |  | 
| 20 | 
            -
             | 
| 20 | 
            +
              break if event_response.events.empty?
         | 
| 21 21 | 
             
            end
         | 
    
        data/examples/oauth.rb
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            require 'dotenv'; Dotenv.load("../.env")
         | 
| 2 | 
            +
            require 'boxr'
         | 
| 3 | 
            +
            require 'uri'
         | 
| 4 | 
            +
            require 'awesome_print'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            #make sure you have BOX_CLIENT_ID and BOX_CLIENT_SECRET set in your .env file
         | 
| 7 | 
            +
            #make sure you have the redirect_uri for your application set to something like https://localhost:1234 in the developer portal
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            oauth_url = Boxr::oauth_url(URI.encode_www_form_component('your-anti-forgery-token'))
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            puts "Copy the URL below and paste into a browser. Go through the OAuth flow using the desired Box account. \
         | 
| 12 | 
            +
            When you are finished your browser will redirect to a 404 error page. This is expected behavior. Look at the URL in the address \
         | 
| 13 | 
            +
            bar and copy the 'code' parameter value. Paste it into the prompt below. You only have 30 seconds to complete this task so be quick about it! \
         | 
| 14 | 
            +
            You will then see your access token and refresh token."
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            puts
         | 
| 17 | 
            +
            puts "URL:  #{oauth_url}"
         | 
| 18 | 
            +
            puts
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            print "Enter the code: "
         | 
| 21 | 
            +
            code = STDIN.gets.chomp.split('=').last
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ap Boxr::get_tokens(code)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
             | 
| 26 | 
            +
             | 
| 27 | 
            +
             | 
    
        data/examples/user_events.rb
    CHANGED
    
    | @@ -8,17 +8,17 @@ cache = LruRedux::Cache.new(1000) | |
| 8 8 |  | 
| 9 9 | 
             
            stream_position = :now
         | 
| 10 10 | 
             
            loop do 
         | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 11 | 
            +
              puts "fetching events..."
         | 
| 12 | 
            +
              event_response = client.user_events(stream_position: stream_position)
         | 
| 13 | 
            +
              event_response.events.each do |event|
         | 
| 14 | 
            +
                key = "/box-event/id/#{event.event_id}"
         | 
| 15 15 |  | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 16 | 
            +
                #we need to de-dupe the events because we will receive multiple events with the same event_id; this is to ensure that we get the event
         | 
| 17 | 
            +
                if (cache.fetch(event.event_id)==nil)
         | 
| 18 | 
            +
                  cache[event.event_id] = true
         | 
| 19 | 
            +
                  puts event.event_type
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              stream_position = event_response.next_stream_position
         | 
| 23 | 
            +
              sleep 2
         | 
| 24 24 | 
             
            end
         | 
    
        data/lib/boxr.rb
    CHANGED
    
    | @@ -16,24 +16,25 @@ require 'boxr/search' | |
| 16 16 | 
             
            require 'boxr/tasks'
         | 
| 17 17 | 
             
            require 'boxr/metadata'
         | 
| 18 18 | 
             
            require 'boxr/events'
         | 
| 19 | 
            +
            require 'boxr/auth'
         | 
| 19 20 |  | 
| 20 21 | 
             
            module Enumerable
         | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 22 | 
            +
              def files
         | 
| 23 | 
            +
                self.select{|i| i.type == 'file'}
         | 
| 24 | 
            +
              end
         | 
| 24 25 |  | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 26 | 
            +
              def folders
         | 
| 27 | 
            +
                self.select{|i| i.type == 'folder'}
         | 
| 28 | 
            +
              end
         | 
| 28 29 |  | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 30 | 
            +
              def web_links
         | 
| 31 | 
            +
                self.select{|i| i.type == 'web_link'}
         | 
| 32 | 
            +
              end
         | 
| 32 33 | 
             
            end
         | 
| 33 34 |  | 
| 34 35 | 
             
            module Boxr
         | 
| 35 36 | 
             
              Oj.default_options = {:mode => :compat }
         | 
| 36 37 |  | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 38 | 
            +
              #The root folder in Box is always identified by 0
         | 
| 39 | 
            +
              ROOT = 0
         | 
| 39 40 | 
             
            end
         | 
    
        data/lib/boxr/auth.rb
    ADDED
    
    | @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module Boxr
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              def self.oauth_url(state, response_type: "code", scope: nil, folder_id: nil, box_client_id: ENV['BOX_CLIENT_ID'])
         | 
| 4 | 
            +
                uri = "https://app.box.com/api/oauth2/authorize?response_type=#{response_type}&state=#{state}&client_id=#{box_client_id}"
         | 
| 5 | 
            +
                uri = uri + "&scope=#{scope}" unless scope.nil?
         | 
| 6 | 
            +
                uri = uri + "&folder_id=#{folder_id}" unless folder_id.nil?
         | 
| 7 | 
            +
                uri
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def self.get_tokens(code, grant_type: "authorization_code", username: nil, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'])
         | 
| 11 | 
            +
                uri = "https://api.box.com/oauth2/token"
         | 
| 12 | 
            +
                body = "code=#{code}&grant_type=#{grant_type}&client_id=#{box_client_id}&client_secret=#{box_client_secret}"
         | 
| 13 | 
            +
                body = body + "&username=#{username}" unless username.nil?
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                auth_post(uri, body)
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def self.refresh_tokens(refresh_token, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'])
         | 
| 19 | 
            +
                uri = "https://api.box.com/oauth2/token"
         | 
| 20 | 
            +
                body = "grant_type=refresh_token&refresh_token=#{refresh_token}&client_id=#{box_client_id}&client_secret=#{box_client_secret}"
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                auth_post(uri, body)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def self.revoke_tokens(token, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'])
         | 
| 26 | 
            +
                uri = "https://api.box.com/oauth2/revoke"
         | 
| 27 | 
            +
                body = "client_id=#{box_client_id}&client_secret=#{box_client_secret}&token=#{token}"
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                auth_post(uri, body)
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              private
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def self.auth_post(uri, body)
         | 
| 35 | 
            +
                client = HTTPClient.new
         | 
| 36 | 
            +
                res = client.post(uri, body: body)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                if(res.status==200)
         | 
| 39 | 
            +
                  body_json = Oj.load(res.body)
         | 
| 40 | 
            +
                  return Hashie::Mash.new(body_json)
         | 
| 41 | 
            +
                else
         | 
| 42 | 
            +
                  raise BoxrException.new(status: res.status, body: res.body, header: res.header)
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            end
         | 
    
        data/lib/boxr/client.rb
    CHANGED
    
    | @@ -1,217 +1,258 @@ | |
| 1 1 | 
             
            module Boxr
         | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 127 | 
            -
             | 
| 128 | 
            -
             | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 149 | 
            -
             | 
| 150 | 
            -
             | 
| 151 | 
            -
             | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 185 | 
            -
             | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 200 | 
            -
             | 
| 201 | 
            -
             | 
| 202 | 
            -
             | 
| 203 | 
            -
             | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 206 | 
            -
             | 
| 207 | 
            -
             | 
| 208 | 
            -
             | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 2 | 
            +
              
         | 
| 3 | 
            +
              class Client
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                attr_reader :access_token, :refresh_token, :box_client_id, :box_client_secret, :identifier, :as_user_id
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                API_URI = "https://api.box.com/2.0"
         | 
| 8 | 
            +
                UPLOAD_URI = "https://upload.box.com/api/2.0"
         | 
| 9 | 
            +
                FILES_URI = "#{API_URI}/files"
         | 
| 10 | 
            +
                FILES_UPLOAD_URI = "#{UPLOAD_URI}/files/content"
         | 
| 11 | 
            +
                FOLDERS_URI = "#{API_URI}/folders"
         | 
| 12 | 
            +
                USERS_URI = "#{API_URI}/users"
         | 
| 13 | 
            +
                GROUPS_URI = "#{API_URI}/groups"
         | 
| 14 | 
            +
                GROUP_MEMBERSHIPS_URI = "#{API_URI}/group_memberships"
         | 
| 15 | 
            +
                COLLABORATIONS_URI = "#{API_URI}/collaborations"
         | 
| 16 | 
            +
                COMMENTS_URI = "#{API_URI}/comments"
         | 
| 17 | 
            +
                SEARCH_URI = "#{API_URI}/search"
         | 
| 18 | 
            +
                TASKS_URI = "#{API_URI}/tasks"
         | 
| 19 | 
            +
                TASK_ASSIGNMENTS_URI = "#{API_URI}/task_assignments"
         | 
| 20 | 
            +
                SHARED_ITEMS_URI = "#{API_URI}/shared_items"
         | 
| 21 | 
            +
                METADATA_URI = "#{API_URI}/files"
         | 
| 22 | 
            +
                EVENTS_URI = "#{API_URI}/events"
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                DEFAULT_LIMIT = 100
         | 
| 25 | 
            +
                FOLDER_ITEMS_LIMIT = 1000
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                FOLDER_AND_FILE_FIELDS = [:type,:id,:sequence_id,:etag,:name,:created_at,:modified_at,:description,
         | 
| 28 | 
            +
                                          :size,:path_collection,:created_by,:modified_by,:trashed_at,:purged_at,
         | 
| 29 | 
            +
                                          :content_created_at,:content_modified_at,:owned_by,:shared_link,:folder_upload_email,
         | 
| 30 | 
            +
                                          :parent,:item_status,:item_collection,:sync_state,:has_collaborations,:permissions,:tags,
         | 
| 31 | 
            +
                                          :sha1,:shared_link,:version_number,:comment_count,:lock,:extension,:is_package,:can_non_owners_invite]
         | 
| 32 | 
            +
                FOLDER_AND_FILE_FIELDS_QUERY = FOLDER_AND_FILE_FIELDS.join(',')
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                COMMENT_FIELDS = [:type,:id,:is_reply_comment,:message,:tagged_message,:created_by,:created_at,:item,:modified_at]
         | 
| 35 | 
            +
                COMMENT_FIELDS_QUERY = COMMENT_FIELDS.join(',')
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                TASK_FIELDS = [:type,:id,:item,:due_at,:action,:message,:task_assignment_collection,:is_completed,:created_by,:created_at]
         | 
| 38 | 
            +
                TASK_FIELDS_QUERY = TASK_FIELDS.join(',')
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                COLLABORATION_FIELDS = [:type,:id,:created_by,:created_at,:modified_at,:expires_at,:status,:accessible_by,:role,:acknowledged_at,:item]
         | 
| 41 | 
            +
                COLLABORATION_FIELDS_QUERY = COLLABORATION_FIELDS.join(',')
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                USER_FIELDS = [:type,:id,:name,:login,:created_at,:modified_at,:role,:language,:timezone,:space_amount,:space_used,
         | 
| 44 | 
            +
                               :max_upload_size,:tracking_codes,:can_see_managed_users,:is_sync_enabled,:is_external_collab_restricted,
         | 
| 45 | 
            +
                               :status,:job_title,:phone,:address,:avatar_uri,:is_exempt_from_device_limits,:is_exempt_from_login_verification,
         | 
| 46 | 
            +
                               :enterprise,:my_tags]
         | 
| 47 | 
            +
                USER_FIELDS_QUERY = USER_FIELDS.join(',')
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                GROUP_FIELDS = [:type, :id, :name, :created_at, :modified_at]
         | 
| 50 | 
            +
                GROUP_FIELDS_QUERY = GROUP_FIELDS.join(',')
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                #Read this to see why the httpclient gem was chosen: http://bibwild.wordpress.com/2012/04/30/ruby-http-performance-shootout-redux/
         | 
| 53 | 
            +
                #All instances of Boxr::Client will use this one class instance of HTTPClient; that way persistent HTTPS connections work.
         | 
| 54 | 
            +
                #Plus, httpclient is thread-safe so we can use the same class instance with multiple instances of Boxr::Client
         | 
| 55 | 
            +
                BOX_CLIENT = HTTPClient.new
         | 
| 56 | 
            +
                BOX_CLIENT.send_timeout = 3600 #one hour; needed for lengthy uploads
         | 
| 57 | 
            +
                BOX_CLIENT.transparent_gzip_decompression = true 
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def self.turn_on_debugging(device=STDOUT)
         | 
| 60 | 
            +
                  BOX_CLIENT.debug_dev = device
         | 
| 61 | 
            +
                  BOX_CLIENT.transparent_gzip_decompression = false
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def self.turn_off_debugging
         | 
| 65 | 
            +
                  BOX_CLIENT.debug_dev = nil
         | 
| 66 | 
            +
                  BOX_CLIENT.transparent_gzip_decompression = true
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def initialize(access_token, refresh_token: nil, box_client_id: ENV['BOX_CLIENT_ID'], box_client_secret: ENV['BOX_CLIENT_SECRET'], 
         | 
| 70 | 
            +
                                identifier: nil, as_user_id: nil, &token_refresh_listener)
         | 
| 71 | 
            +
                  @access_token = access_token
         | 
| 72 | 
            +
                  @refresh_token = refresh_token
         | 
| 73 | 
            +
                  @box_client_id = box_client_id
         | 
| 74 | 
            +
                  @box_client_secret = box_client_secret
         | 
| 75 | 
            +
                  @identifier = identifier
         | 
| 76 | 
            +
                  @as_user_id = as_user_id
         | 
| 77 | 
            +
                  @token_refresh_listener = token_refresh_listener
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
             | 
| 81 | 
            +
                private
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def get(uri, query: nil, success_codes: [200], process_response: true, if_match: nil, box_api_header: nil)
         | 
| 84 | 
            +
                  res = with_auto_token_refresh do
         | 
| 85 | 
            +
                    headers = standard_headers()
         | 
| 86 | 
            +
                    headers['If-Match'] = if_match unless if_match.nil?
         | 
| 87 | 
            +
                    headers['BoxApi'] = box_api_header unless box_api_header.nil?
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    BOX_CLIENT.get(uri, query: query, header: headers)
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  check_response_status(res, success_codes)
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  if process_response
         | 
| 95 | 
            +
                    return processed_response res
         | 
| 96 | 
            +
                  else
         | 
| 97 | 
            +
                    return res.body, res
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def get_with_pagination(uri, query: {}, limit: DEFAULT_LIMIT)
         | 
| 102 | 
            +
                  entries = []
         | 
| 103 | 
            +
                  offset = 0
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                  begin
         | 
| 106 | 
            +
                    query[:limit] = limit
         | 
| 107 | 
            +
                    query[:offset] = offset
         | 
| 108 | 
            +
                    res = with_auto_token_refresh do
         | 
| 109 | 
            +
                      headers = standard_headers()
         | 
| 110 | 
            +
                      BOX_CLIENT.get(uri, query: query, header: headers)
         | 
| 111 | 
            +
                    end
         | 
| 112 | 
            +
                    
         | 
| 113 | 
            +
                    if (res.status==200)
         | 
| 114 | 
            +
                      body_json = Oj.load(res.body)
         | 
| 115 | 
            +
                      total_count = body_json["total_count"]
         | 
| 116 | 
            +
                      offset = offset + limit
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                      entries << body_json["entries"]
         | 
| 119 | 
            +
                    else
         | 
| 120 | 
            +
                      raise BoxrException.new(status: res.status, body: res.body, header: res.header)
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
                  end until offset - total_count >= 0
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                  entries.flatten.map{|i| Hashie::Mash.new(i)}
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def post(uri, body, query: nil, success_codes: [201], process_body: true, content_md5: nil, content_type: nil, if_match: nil)
         | 
| 128 | 
            +
                  body = Oj.dump(body) if process_body
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                  res = with_auto_token_refresh do
         | 
| 131 | 
            +
                    headers = standard_headers()
         | 
| 132 | 
            +
                    headers['If-Match'] = if_match unless if_match.nil?
         | 
| 133 | 
            +
                    headers["Content-MD5"] = content_md5 unless content_md5.nil?
         | 
| 134 | 
            +
                    headers["Content-Type"] = content_type unless content_type.nil?
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                    BOX_CLIENT.post(uri, body: body, query: query, header: headers)
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  check_response_status(res, success_codes)
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  processed_response res
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                def put(uri, body, query: nil, success_codes: [200], content_type: nil, if_match: nil)
         | 
| 145 | 
            +
                  res = with_auto_token_refresh do
         | 
| 146 | 
            +
                    headers = standard_headers()
         | 
| 147 | 
            +
                    headers['If-Match'] = if_match unless if_match.nil?
         | 
| 148 | 
            +
                    headers["Content-Type"] = content_type unless content_type.nil?
         | 
| 149 | 
            +
                    
         | 
| 150 | 
            +
                    BOX_CLIENT.put(uri, body: Oj.dump(body), query: query, header: headers)
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                  check_response_status(res, success_codes)
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                  processed_response res
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                def delete(uri, query: nil, success_codes: [204], if_match: nil)
         | 
| 159 | 
            +
                  res = with_auto_token_refresh do
         | 
| 160 | 
            +
                    headers = standard_headers()
         | 
| 161 | 
            +
                    headers['If-Match'] = if_match unless if_match.nil?
         | 
| 162 | 
            +
                    
         | 
| 163 | 
            +
                    BOX_CLIENT.delete(uri, query: query, header: headers)
         | 
| 164 | 
            +
                  end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  check_response_status(res, success_codes)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                  processed_response res
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 171 | 
            +
                def options(uri, body, success_codes: [200])
         | 
| 172 | 
            +
                  res = with_auto_token_refresh do
         | 
| 173 | 
            +
                    headers = standard_headers()
         | 
| 174 | 
            +
                    BOX_CLIENT.options(uri, body: Oj.dump(body), header: headers)
         | 
| 175 | 
            +
                  end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                  check_response_status(res, success_codes)
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  processed_response res
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                def standard_headers()
         | 
| 183 | 
            +
                  headers = {"Authorization" => "Bearer #{@access_token}"}
         | 
| 184 | 
            +
                  headers['As-User'] = "#{@as_user_id}" unless @as_user_id.nil?
         | 
| 185 | 
            +
                  headers
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                def with_auto_token_refresh
         | 
| 189 | 
            +
                  return yield unless @refresh_token
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                  res = yield
         | 
| 192 | 
            +
                  if res.status == 401
         | 
| 193 | 
            +
                    auth_header = res.header['WWW-Authenticate'][0]
         | 
| 194 | 
            +
                    if auth_header && auth_header.include?('invalid_token')
         | 
| 195 | 
            +
                      new_tokens = Boxr::refresh_tokens(@refresh_token, box_client_id: box_client_id, box_client_secret: box_client_secret)
         | 
| 196 | 
            +
                      @access_token = new_tokens.access_token
         | 
| 197 | 
            +
                      @refresh_token = new_tokens.refresh_token
         | 
| 198 | 
            +
                      @token_refresh_listener.call(@access_token, @refresh_token, @identifier) if @token_refresh_listener
         | 
| 199 | 
            +
                      res = yield
         | 
| 200 | 
            +
                    end
         | 
| 201 | 
            +
                  end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                  res
         | 
| 204 | 
            +
                end
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                def check_response_status(res, success_codes)
         | 
| 207 | 
            +
                  raise BoxrException.new(status: res.status, body: res.body, header: res.header) unless success_codes.include?(res.status)
         | 
| 208 | 
            +
                end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                def processed_response(res)
         | 
| 211 | 
            +
                  body_json = Oj.load(res.body)
         | 
| 212 | 
            +
                  return Hashie::Mash.new(body_json), res
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                def build_fields_query(fields, all_fields_query)
         | 
| 216 | 
            +
                  if fields == :all
         | 
| 217 | 
            +
                    {:fields => all_fields_query}
         | 
| 218 | 
            +
                  elsif fields.is_a?(Array) && fields.length > 0
         | 
| 219 | 
            +
                    {:fields => fields.join(',')}
         | 
| 220 | 
            +
                  else
         | 
| 221 | 
            +
                    {}
         | 
| 222 | 
            +
                  end
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
             | 
| 225 | 
            +
                def restore_trashed_item(uri, name, parent_id)
         | 
| 226 | 
            +
                  attributes = {}
         | 
| 227 | 
            +
                  attributes[:name] = name unless name.nil?
         | 
| 228 | 
            +
                  attributes[:parent] = {id: parent_id} unless parent_id.nil?
         | 
| 229 | 
            +
                  
         | 
| 230 | 
            +
                  restored_item, response = post uri, attributes
         | 
| 231 | 
            +
                  restored_item
         | 
| 232 | 
            +
                end
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                def create_shared_link(uri, item_id, access, unshared_at, can_download, can_preview)
         | 
| 235 | 
            +
                  if access.nil?
         | 
| 236 | 
            +
                    attributes = {shared_link: {}}
         | 
| 237 | 
            +
                  else
         | 
| 238 | 
            +
                    attributes = {shared_link: {access: access}}
         | 
| 239 | 
            +
                    attributes[:shared_link][:unshared_at] = unshared_at.to_datetime.rfc3339 unless unshared_at.nil?
         | 
| 240 | 
            +
                    attributes[:shared_link][:permissions] = {} unless can_download.nil? && can_preview.nil?
         | 
| 241 | 
            +
                    attributes[:shared_link][:permissions][:can_download] = can_download unless can_download.nil?
         | 
| 242 | 
            +
                    attributes[:shared_link][:permissions][:can_preview] = can_preview unless can_preview.nil?
         | 
| 243 | 
            +
                  end
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                  updated_item, response = put uri, attributes
         | 
| 246 | 
            +
                  updated_item
         | 
| 247 | 
            +
                end
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                def disable_shared_link(uri, item_id)
         | 
| 250 | 
            +
                  attributes = {shared_link: nil}
         | 
| 251 | 
            +
             | 
| 252 | 
            +
                  updated_item, response = put uri, attributes
         | 
| 253 | 
            +
                  updated_item
         | 
| 254 | 
            +
                end
         | 
| 255 | 
            +
             | 
| 256 | 
            +
              end
         | 
| 216 257 |  | 
| 217 258 | 
             
            end
         |