box-com 0.0.7
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 +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/box/authorization.rb +64 -0
- data/lib/box/client.rb +168 -0
- data/lib/box/exceptions.rb +16 -0
- data/lib/box/file.rb +61 -0
- data/lib/box/folder.rb +65 -0
- data/lib/box/item.rb +40 -0
- data/lib/box/session.rb +72 -0
- data/lib/box/version.rb +3 -0
- data/lib/box.rb +61 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a22a998fddabe194a554b6f6a6bdc196754f147f
|
4
|
+
data.tar.gz: 609f5df6720094f297bb2b0f7ec9296508221e76
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e80c6bab9290a0b62d35a95b80ac945eada2b5e78d5a1a0967fa8eb49e4a410cc160caeb1254cf0dc4d052ae4a8d20b749db79c17c64800eb42d79007ed63f90
|
7
|
+
data.tar.gz: 10b6b0f5c7079ae0e4553c5deb48c082beb7395b89137f8a00740ff518e4a1c8eb62e15d5e39f176751890fabab24db6eae3a45a37ad3b144abf05a78b66317d
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 David Michael
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Box
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'box'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install box
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( http://github.com/<my-github-username>/box/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module Box
|
3
|
+
class Authorization
|
4
|
+
|
5
|
+
def self.authorize(config = {})
|
6
|
+
username, password = config[:username], config[:password]
|
7
|
+
raise "Unable to get auth tokens without username and password" unless username && password
|
8
|
+
|
9
|
+
require 'mechanize'
|
10
|
+
|
11
|
+
puts '... attempting to authorize with username and password'
|
12
|
+
client_id, client_secret = config[:client_id], config[:client_secret]
|
13
|
+
|
14
|
+
|
15
|
+
agent = Mechanize::new
|
16
|
+
session = Session.new(config)
|
17
|
+
|
18
|
+
# Get the authorization URL from Box by specifying redirect URL
|
19
|
+
# as the arbitrary but working Chase bank home page - this must match the address at Box
|
20
|
+
# authorize_url = box_session.authorize_url('https://anywhere.airdye.com/oauth2callback')
|
21
|
+
authorize_url = session.authorize_url(redirect_uri: 'https://www.chase.com')
|
22
|
+
|
23
|
+
# process the first login screen
|
24
|
+
login_page = agent.get(authorize_url)
|
25
|
+
|
26
|
+
# get the login form where you enter the username and password
|
27
|
+
login_form = login_page.form_with(name: 'login_form')
|
28
|
+
login_form.login = username
|
29
|
+
login_form.password = password
|
30
|
+
|
31
|
+
# submit the form and get the allow/deny page back
|
32
|
+
allow_page = agent.submit(login_form)
|
33
|
+
|
34
|
+
# find the form that allows consent
|
35
|
+
consent_form = allow_page.form_with(name: 'consent_form')
|
36
|
+
|
37
|
+
# now find the button that submits the allow page with consent
|
38
|
+
accept_button = consent_form.button_with(name: 'consent_accept')
|
39
|
+
|
40
|
+
# Submit the form to cause the redirection with authentication code
|
41
|
+
redirpage = agent.submit(consent_form, accept_button)
|
42
|
+
|
43
|
+
# Use the CGI module to get a hash of the variables (stuff after ?)
|
44
|
+
# and then the authentication code is embedded in [" and "] so
|
45
|
+
# strip those
|
46
|
+
code_query = CGI::parse(redirpage.uri.query)['code'].to_s
|
47
|
+
code = code_query[2,code_query.length-4]
|
48
|
+
|
49
|
+
# get the box access token using the authentication code
|
50
|
+
session.aquire_access_token(code)
|
51
|
+
|
52
|
+
# print the tokens to show we have them
|
53
|
+
p session.access_token
|
54
|
+
p session.refresh_token
|
55
|
+
|
56
|
+
Box::Session.on_token_refresh.call(session.access_token, session.refresh_token)
|
57
|
+
|
58
|
+
# Create a new Box client based on the authenticated session
|
59
|
+
# ap Box.client.root.items
|
60
|
+
|
61
|
+
return session.oauth2_access_token
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/box/client.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
module Box
|
5
|
+
class Client
|
6
|
+
VERSION = '2.0'
|
7
|
+
attr_accessor :session
|
8
|
+
|
9
|
+
def initialize(session)
|
10
|
+
@session = session
|
11
|
+
end
|
12
|
+
|
13
|
+
def root
|
14
|
+
Folder.new(self, id: 0)
|
15
|
+
end
|
16
|
+
|
17
|
+
def walk(root, &block)
|
18
|
+
root.items.each do |item|
|
19
|
+
if item.folder?
|
20
|
+
walk(item, &block)
|
21
|
+
elsif item.file?
|
22
|
+
yield item
|
23
|
+
else
|
24
|
+
puts "Unknown item type #{item.id}:#{item.type}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Starting at the "root" of Box which is always "All Files", make successive requests untl you have reached the
|
30
|
+
# final path in the input
|
31
|
+
def folder(path) # /path/to/folder
|
32
|
+
path = Pathname(path).each_filename.to_a
|
33
|
+
folder = root
|
34
|
+
path.each do |name|
|
35
|
+
folder = folder.folders.select {|folder| folder.name == name}.first
|
36
|
+
return nil unless folder
|
37
|
+
end
|
38
|
+
folder
|
39
|
+
end
|
40
|
+
|
41
|
+
def search(query, options = {})
|
42
|
+
params = options.merge({query: query})
|
43
|
+
|
44
|
+
response = get('search', params)
|
45
|
+
parse_items(response.body)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Process the Box "items" returned from a request
|
49
|
+
def parse_items(results)
|
50
|
+
return [] if results['entries'].empty?
|
51
|
+
results['entries'].reduce([]) do |entries, entry|
|
52
|
+
entries << case entry['type']
|
53
|
+
when 'file' then Box::File.new(self, entry)
|
54
|
+
when 'folder' then Box::Folder.new(self, entry)
|
55
|
+
end
|
56
|
+
entries
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def connection
|
61
|
+
conn = Faraday.new(Box::API_URL) do |builder|
|
62
|
+
builder.request :json
|
63
|
+
builder.request :multipart
|
64
|
+
# builder.response :logger
|
65
|
+
builder.response :json, :content_type => /\bjson$/
|
66
|
+
# What a joke. This must be LAST to avoid encoding errors in JSON request body
|
67
|
+
builder.adapter :net_http
|
68
|
+
end
|
69
|
+
|
70
|
+
conn.headers['Authorization'] = "Bearer #{@session.access_token}"
|
71
|
+
conn
|
72
|
+
end
|
73
|
+
|
74
|
+
def make_uri(path)
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
def get(path, params = {}, retries = 0)
|
79
|
+
request('GET', path, params)
|
80
|
+
end
|
81
|
+
|
82
|
+
def post(path, params = {}, retries = 0)
|
83
|
+
request('POST', path, params)
|
84
|
+
end
|
85
|
+
|
86
|
+
def put(path, params = {}, retries = 0)
|
87
|
+
request('PUT', path, params)
|
88
|
+
end
|
89
|
+
|
90
|
+
def delete(path, params = {}, retries = 0)
|
91
|
+
request('DELETE', path, params)
|
92
|
+
end
|
93
|
+
|
94
|
+
def upload(params = {}, retries = 0)
|
95
|
+
# Basic parameters
|
96
|
+
local_path, content_type, file_name, parent_id = params[:local_path], params[:content_type], params[:file_name], params[:parent_id]
|
97
|
+
# If there is a file_id, it means we want to replace it.
|
98
|
+
uri = if params[:box_id]
|
99
|
+
"https://upload.box.com/api/2.0/files/#{params[:box_id]}/content"
|
100
|
+
else
|
101
|
+
'https://upload.box.com/api/2.0/files/content'
|
102
|
+
end
|
103
|
+
|
104
|
+
puts "[Box.com] POST #{uri}"
|
105
|
+
|
106
|
+
# Construct the payload
|
107
|
+
payload = {
|
108
|
+
filename: Faraday::UploadIO.new(local_path, content_type, file_name),
|
109
|
+
parent_id: parent_id
|
110
|
+
}
|
111
|
+
|
112
|
+
response = connection.post(uri, payload) do |request|
|
113
|
+
request.headers['Content-Type'] = 'multipart/form-data'
|
114
|
+
end
|
115
|
+
|
116
|
+
case response.status
|
117
|
+
when 401
|
118
|
+
try_token_refresh!
|
119
|
+
return upload(params, retries + 1) if retries == 0
|
120
|
+
else
|
121
|
+
return handle_response(response)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Generic HTTP request method with retries for bad authorization
|
126
|
+
def request(method, path, params = {}, retries = 0)
|
127
|
+
uri = Addressable::URI.parse(::File.join(VERSION, path))
|
128
|
+
if method == 'GET'
|
129
|
+
uri.query_values = params.reduce({}){|hash, (k,v)| hash[k] = v.to_s; hash}
|
130
|
+
# params = {}
|
131
|
+
end
|
132
|
+
|
133
|
+
puts "[Box.com] #{method} #{::File.join(Box::API_URL, uri.to_s)}"
|
134
|
+
response = connection.send(method.downcase, uri.to_s, params)
|
135
|
+
|
136
|
+
case response.status
|
137
|
+
when 401
|
138
|
+
try_token_refresh!
|
139
|
+
return request(method, path, params, retries + 1) if retries == 0
|
140
|
+
else
|
141
|
+
return handle_response(response)
|
142
|
+
end
|
143
|
+
# TODO: We need to retry connection failures - or at least catch them
|
144
|
+
# rescue Faraday::ConnectionFailed => e
|
145
|
+
end
|
146
|
+
|
147
|
+
def try_token_refresh!
|
148
|
+
@session.refresh_token!
|
149
|
+
rescue OAuth2::Error => e
|
150
|
+
raise "Sorry, could not refresh tokens: #{e.message}"
|
151
|
+
end
|
152
|
+
|
153
|
+
def handle_response(response)
|
154
|
+
case response.status
|
155
|
+
when 400
|
156
|
+
raise Box::MalformedAuthHeaders, response.headers
|
157
|
+
when 404
|
158
|
+
raise Box::ResourceNotFound, JSON.dump(response.body)
|
159
|
+
when 409
|
160
|
+
raise Box::NameConflict, JSON.dump(response.body)
|
161
|
+
when 500
|
162
|
+
ap response.body
|
163
|
+
end
|
164
|
+
return response
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
data/lib/box/file.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Box
|
2
|
+
class File < Item
|
3
|
+
def_delegators :@metadata, :sha1, :name, :size, :etag, :parent
|
4
|
+
|
5
|
+
def self.download_uri(id)
|
6
|
+
response = Box.client.get("/files/#{id}/content")
|
7
|
+
uri = nil
|
8
|
+
uri = response.headers['location'] if response.status == 302
|
9
|
+
uri
|
10
|
+
end
|
11
|
+
|
12
|
+
def size
|
13
|
+
@metadata['size']
|
14
|
+
end
|
15
|
+
|
16
|
+
def path
|
17
|
+
"/" + path_names.join('/')
|
18
|
+
end
|
19
|
+
|
20
|
+
def path_with_file
|
21
|
+
::File.join(path, name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def paths
|
25
|
+
@metadata['path_collection']['entries']
|
26
|
+
end
|
27
|
+
|
28
|
+
def path_names
|
29
|
+
paths.map {|path| path['name']}
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.delete_existing(id)
|
33
|
+
Box.client.delete("files/#{id}")
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# Ruby is such a pain in the ass with it's loosy goosy type
|
38
|
+
# @return [Box::File] The newly created file on Box
|
39
|
+
def copy_to(folder, options = {})
|
40
|
+
raise Box::ArgumentError, 'folder must be a Box::Folder' unless folder.is_a?(Box::Folder)
|
41
|
+
raise Box::ArgumentError, 'options must be a Hash' unless options.is_a?(Hash)
|
42
|
+
|
43
|
+
folder_id = folder.id
|
44
|
+
|
45
|
+
params = {parent: {id: folder_id}, name: options[:name]}
|
46
|
+
# This response is a Box file object
|
47
|
+
response = @client.post("files/#{id}/copy", params)
|
48
|
+
Box::File.new(@client, response.body)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Since this is just an update, this method is idempotent always returning a file
|
52
|
+
def move_to(folder, options = {})
|
53
|
+
folder_id = (folder.is_a?(Box::Folder)) ? folder.id : folder
|
54
|
+
|
55
|
+
response = @client.put("files/#{id}", parent:{id: folder_id})
|
56
|
+
Box::File.new(@client, response.body)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/box/folder.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Box
|
2
|
+
class Folder < Item
|
3
|
+
LIMIT = 1000
|
4
|
+
def_delegators :@metadata, :name
|
5
|
+
|
6
|
+
def load_info!
|
7
|
+
@client.get("/folders/#{id}")
|
8
|
+
end
|
9
|
+
|
10
|
+
# Check to see if an item of the same name in the folder
|
11
|
+
def has_item?(name)
|
12
|
+
items.find {|item| item.name == name}
|
13
|
+
end
|
14
|
+
|
15
|
+
def subfolder(folder_name)
|
16
|
+
folders = items.select {|item| item.folder? and item.name == folder_name}
|
17
|
+
return nil if folders.empty?
|
18
|
+
folders.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_or_create_subfolder(folder_name)
|
22
|
+
folder = subfolder(folder_name)
|
23
|
+
return folder unless folder.nil?
|
24
|
+
|
25
|
+
puts "[Box.com] Creating subfolder in #{self.name} for #{folder_name}"
|
26
|
+
response = @client.post('folders', {name: folder_name, parent:{id: self.id}})
|
27
|
+
|
28
|
+
if response.status == 201 # created
|
29
|
+
folder = Box::Folder.new(@client, response.body)
|
30
|
+
puts "[Box.com] Created folder for #{folder_name} in #{name} as #{folder.id}"
|
31
|
+
folder
|
32
|
+
else
|
33
|
+
puts "[Box.com] Error creating folder, #{response.body}"
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# Warning: This gets on all files for a directory with no limit by recursively calling itself until it reaches
|
40
|
+
# the limit
|
41
|
+
def items(params = {}, collection = [])
|
42
|
+
# Format params defaults
|
43
|
+
params = {fields: 'sha1,name,path_collection,size', limit: LIMIT, offset: 0}.merge(params)
|
44
|
+
# Add expected fields and limit
|
45
|
+
response = @client.get("/folders/#{id}/items", params)
|
46
|
+
ap response
|
47
|
+
# Add the results to the total collection
|
48
|
+
collection.push *@client.parse_items(response.body)
|
49
|
+
|
50
|
+
total_count = response.body['total_count']
|
51
|
+
offset = (LIMIT * (params[:offset] + 1))
|
52
|
+
|
53
|
+
if total_count > offset
|
54
|
+
puts "[Box.com] Recursively calling for items in folder #{name} - #{LIMIT}, #{offset}, #{total_count}"
|
55
|
+
return self.items({offset: offset}, collection)
|
56
|
+
end
|
57
|
+
|
58
|
+
collection
|
59
|
+
end
|
60
|
+
|
61
|
+
def folders
|
62
|
+
items.select {|item| item.type == 'folder' }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/box/item.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Box
|
4
|
+
class Item
|
5
|
+
attr_accessor :client, :metadata
|
6
|
+
extend Forwardable
|
7
|
+
extend Memoist
|
8
|
+
|
9
|
+
def self.type
|
10
|
+
self.name.demodulize.downcase
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(*args)
|
14
|
+
if args.size == 1
|
15
|
+
@client, @metadata = Box.client, Hashie::Mash.new(args[0])
|
16
|
+
else
|
17
|
+
@client, @metadata = args[0], Hashie::Mash.new(args[1])
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def folder?
|
23
|
+
type == 'folder'
|
24
|
+
end
|
25
|
+
|
26
|
+
def file?
|
27
|
+
type == 'file'
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.find(id)
|
31
|
+
response = Box.client.get("#{type.pluralize}/#{id}")
|
32
|
+
self.new(Box.client, response.body)
|
33
|
+
rescue Box::ResourceNotFound => e
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def_delegators :@metadata, :id, :type
|
39
|
+
end
|
40
|
+
end
|
data/lib/box/session.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
module Box
|
2
|
+
class Session
|
3
|
+
extend Memoist
|
4
|
+
attr_accessor :client_id, :client_secret, :access_token, :refresh_token, :on_token_refresh, :oauth2_access_token
|
5
|
+
attr_accessor :config
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :on_token_refresh
|
9
|
+
@on_token_refresh = -> (access_token, refresh_token) {}
|
10
|
+
end
|
11
|
+
|
12
|
+
OAUTH2_URLS = {
|
13
|
+
site: 'https://www.box.com',
|
14
|
+
authorize_url: '/api/oauth2/authorize',
|
15
|
+
token_url: '/api/oauth2/token'
|
16
|
+
}
|
17
|
+
|
18
|
+
def initialize(config = {})
|
19
|
+
@config = config
|
20
|
+
# We must have at least these variables
|
21
|
+
@client_id = config[:client_id]
|
22
|
+
@client_secret = config[:client_secret]
|
23
|
+
@access_token = config[:access_token]
|
24
|
+
@refresh_token = config[:refresh_token]
|
25
|
+
|
26
|
+
if @access_token
|
27
|
+
@oauth2_access_token = OAuth2::AccessToken.new(oauth2_client, @access_token, {refresh_token: @refresh_token})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def oauth2_client
|
32
|
+
OAuth2::Client.new(@client_id, @client_secret, OAUTH2_URLS.dup)
|
33
|
+
end
|
34
|
+
memoize :oauth2_client
|
35
|
+
|
36
|
+
# {redirect_uri: value}
|
37
|
+
def authorize_url(options = {})
|
38
|
+
oauth2_client.auth_code.authorize_url(options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [OAuth2::AccessToken]
|
42
|
+
def aquire_access_token(code)
|
43
|
+
@oauth2_access_token = oauth2_client.auth_code.get_token(code)
|
44
|
+
set_tokens!
|
45
|
+
@oauth2_access_token
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_tokens!
|
49
|
+
@access_token = @oauth2_access_token.token
|
50
|
+
@refresh_token = @oauth2_access_token.refresh_token
|
51
|
+
end
|
52
|
+
|
53
|
+
def refresh_token!
|
54
|
+
@oauth2_access_token = @oauth2_access_token.refresh!
|
55
|
+
set_tokens!
|
56
|
+
Box::Session.on_token_refresh.call(@oauth2_access_token.token, @oauth2_access_token.refresh_token)
|
57
|
+
@oauth2_access_token
|
58
|
+
rescue OAuth2::Error => e
|
59
|
+
if e.code == 'invalid_client' || ((e.code == 'invalid_grant') && (e.description == 'Refresh token has expired' || e.description == 'Invalid refresh token'))
|
60
|
+
raise e if @config[:disable_auth]
|
61
|
+
puts "Error authenticating Box -> #{e.message}"
|
62
|
+
puts 'Attempting to reauthorize and get new tokens'
|
63
|
+
@oauth2_access_token = Box::Authorization.authorize(config)
|
64
|
+
set_tokens!
|
65
|
+
return @oauth2_access_token
|
66
|
+
else
|
67
|
+
raise e
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/lib/box/version.rb
ADDED
data/lib/box.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'memoist'
|
2
|
+
require 'hashie'
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday_middleware'
|
5
|
+
require 'addressable/uri'
|
6
|
+
require 'oauth2'
|
7
|
+
|
8
|
+
$LOAD_PATH << File.dirname(__FILE__)
|
9
|
+
require 'box/version'
|
10
|
+
|
11
|
+
module Box
|
12
|
+
API_URL = 'https://api.box.com'
|
13
|
+
UPLOAD_URL = 'https://upload.box.com/api/2.0'
|
14
|
+
ISO_8601_TEST = Regexp.new(/^[0-9]{4}-[0-9]{2}-[0-9]{2}T/)
|
15
|
+
|
16
|
+
class << self
|
17
|
+
extend Memoist
|
18
|
+
|
19
|
+
def client(config = {})
|
20
|
+
# Accounts for both string and Symbol keyed hashes.
|
21
|
+
# This is basically stringify_keys, just less efficient
|
22
|
+
config = Hashie::Mash.new(config)
|
23
|
+
# You can either pass in the config, or set it from the environment variables
|
24
|
+
config = {
|
25
|
+
access_token: config['access_token'] || ENV['BOX_ACCESS_TOKEN'],
|
26
|
+
refresh_token: config['refresh_token'] || ENV['BOX_REFRESH_TOKEN'],
|
27
|
+
client_id: config['client_id'] || ENV['BOX_CLIENT_ID'],
|
28
|
+
client_secret: config['client_secret'] || ENV['BOX_CLIENT_SECRET'],
|
29
|
+
username: config['username'] || ENV['BOX_USERNAME'],
|
30
|
+
password: config['password'] || ENV['BOX_PASSWORD']
|
31
|
+
}
|
32
|
+
|
33
|
+
# Box::Authorization.authorize client_id, client_secret
|
34
|
+
session = create_session(config)
|
35
|
+
Box::Client.new(session)
|
36
|
+
end
|
37
|
+
# memoize :client
|
38
|
+
|
39
|
+
def create_session(config = {})
|
40
|
+
Box::Session.new config
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'box/exceptions'
|
47
|
+
require 'box/client'
|
48
|
+
require 'box/session'
|
49
|
+
require 'box/authorization'
|
50
|
+
require 'box/item'
|
51
|
+
require 'box/folder'
|
52
|
+
require 'box/file'
|
53
|
+
|
54
|
+
Box::Session.on_token_refresh = -> (access_token,refresh_token) {
|
55
|
+
puts 'Box::Session.on_token_refresh called with'
|
56
|
+
puts access_token
|
57
|
+
puts refresh_token
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
|
metadata
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: box-com
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Michael
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-06-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: memoist
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.9.3
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.9.3
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mechanize
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.7.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.7.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faraday
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.9.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.9.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: faraday_middleware
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 0.9.1
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 0.9.1
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: addressable
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "<="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 2.2.4
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "<="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.2.4
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: hashie
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: oauth2
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.9.3
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.9.3
|
139
|
+
description: Write a longer description. Optional.
|
140
|
+
email:
|
141
|
+
- david.michael@giantmachines.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- Gemfile
|
147
|
+
- LICENSE.txt
|
148
|
+
- README.md
|
149
|
+
- Rakefile
|
150
|
+
- lib/box.rb
|
151
|
+
- lib/box/authorization.rb
|
152
|
+
- lib/box/client.rb
|
153
|
+
- lib/box/exceptions.rb
|
154
|
+
- lib/box/file.rb
|
155
|
+
- lib/box/folder.rb
|
156
|
+
- lib/box/item.rb
|
157
|
+
- lib/box/session.rb
|
158
|
+
- lib/box/version.rb
|
159
|
+
homepage: ''
|
160
|
+
licenses:
|
161
|
+
- MIT
|
162
|
+
metadata: {}
|
163
|
+
post_install_message:
|
164
|
+
rdoc_options: []
|
165
|
+
require_paths:
|
166
|
+
- lib
|
167
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
version: '0'
|
172
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '0'
|
177
|
+
requirements: []
|
178
|
+
rubyforge_project:
|
179
|
+
rubygems_version: 2.2.2
|
180
|
+
signing_key:
|
181
|
+
specification_version: 4
|
182
|
+
summary: Write a short summary. Required.
|
183
|
+
test_files: []
|