lti-ruby-box 1.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.travis.yml +6 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +51 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +349 -0
- data/Rakefile +32 -0
- data/VERSION +1 -0
- data/lib/ruby-box.rb +22 -0
- data/lib/ruby-box/client.rb +167 -0
- data/lib/ruby-box/collaboration.rb +19 -0
- data/lib/ruby-box/comment.rb +14 -0
- data/lib/ruby-box/discussion.rb +15 -0
- data/lib/ruby-box/event.rb +4 -0
- data/lib/ruby-box/event_response.rb +17 -0
- data/lib/ruby-box/exceptions.rb +22 -0
- data/lib/ruby-box/file.rb +96 -0
- data/lib/ruby-box/folder.rb +113 -0
- data/lib/ruby-box/item.rb +181 -0
- data/lib/ruby-box/login_token.rb +9 -0
- data/lib/ruby-box/session.rb +137 -0
- data/lib/ruby-box/shared_link.rb +10 -0
- data/lib/ruby-box/user.rb +16 -0
- data/lib/ruby-box/web_link.rb +4 -0
- data/lti-ruby-box.gemspec +101 -0
- metadata +184 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'addressable/uri'
|
3
|
+
|
4
|
+
module RubyBox
|
5
|
+
class Item
|
6
|
+
|
7
|
+
@@has_many = []
|
8
|
+
@@has_many_paginated = []
|
9
|
+
|
10
|
+
def initialize( session, raw_item )
|
11
|
+
@session = session
|
12
|
+
@raw_item = raw_item
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.has_many(*keys)
|
16
|
+
keys.each {|key| @@has_many << key.to_s}
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.has_many_paginated(*keys)
|
20
|
+
keys.each {|key| @@has_many_paginated << key.to_s}
|
21
|
+
end
|
22
|
+
|
23
|
+
def move_to( folder_id, name=nil )
|
24
|
+
# Allow either a folder_id or a folder object
|
25
|
+
# to be passed in.
|
26
|
+
folder_id = folder_id.id if folder_id.instance_of?(RubyBox::Folder)
|
27
|
+
|
28
|
+
self.name = name if name
|
29
|
+
self.parent = {"id" => folder_id}
|
30
|
+
|
31
|
+
update
|
32
|
+
end
|
33
|
+
|
34
|
+
def update
|
35
|
+
reload_meta unless etag
|
36
|
+
|
37
|
+
url = "#{RubyBox::API_URL}/#{resource_name}/#{id}"
|
38
|
+
uri = URI.parse(url)
|
39
|
+
|
40
|
+
request = Net::HTTP::Put.new(uri.path, {
|
41
|
+
"if-match" => etag,
|
42
|
+
"Content-Type" => 'application/json'
|
43
|
+
})
|
44
|
+
request.body = JSON.dump(serialize)
|
45
|
+
|
46
|
+
@raw_item = @session.request(uri, request)
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
def create
|
51
|
+
url = "#{RubyBox::API_URL}/#{resource_name}"
|
52
|
+
uri = URI.parse(url)
|
53
|
+
request = Net::HTTP::Post.new( uri.request_uri )
|
54
|
+
request.body = JSON.dump(@raw_item)
|
55
|
+
resp = @session.request(uri, request)
|
56
|
+
@raw_item = resp
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(opts={})
|
61
|
+
url = "#{RubyBox::API_URL}/#{resource_name}/#{id}"
|
62
|
+
url = "#{url}#{Addressable::URI.new(:query_values => opts).to_s}" unless opts.keys.empty?
|
63
|
+
resp = @session.delete( url )
|
64
|
+
end
|
65
|
+
|
66
|
+
def reload_meta
|
67
|
+
url = "#{RubyBox::API_URL}/#{resource_name}/#{@raw_item['id']}"
|
68
|
+
@raw_item = @session.get( url )
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
def method_missing(method, *args, &block)
|
73
|
+
key = method.to_s
|
74
|
+
|
75
|
+
# Support has many and paginated has many relationships.
|
76
|
+
return many(key) if @@has_many.include?(key)
|
77
|
+
return paginated(key, args[0] || 100, args[1] || 0, args[2]) if @@has_many_paginated.include?(key)
|
78
|
+
|
79
|
+
# update @raw_item hash if this appears to be a setter.
|
80
|
+
setter = method.to_s.end_with?('=')
|
81
|
+
key = key[0...-1] if setter
|
82
|
+
@raw_item[key] = args[0] if setter and update_fields.include?(key)
|
83
|
+
|
84
|
+
# we may have a mini version of the object loaded, fix this.
|
85
|
+
reload_meta if @raw_item[key].nil? and has_mini_format?
|
86
|
+
|
87
|
+
if @raw_item[key].kind_of?(Hash)
|
88
|
+
return RubyBox::Item.factory(@session, @raw_item[key])
|
89
|
+
elsif RubyBox::ISO_8601_TEST.match(@raw_item[key].to_s)
|
90
|
+
return Time.parse(@raw_item[key])
|
91
|
+
else
|
92
|
+
return @raw_item[key]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# see http://developers.box.com/docs/#folders-create-a-shared-link-for-a-folder
|
97
|
+
# for a list of valid options.
|
98
|
+
def create_shared_link(opts={})
|
99
|
+
raise UnshareableResource unless ['folder', 'file'].include?(type)
|
100
|
+
|
101
|
+
opts = {
|
102
|
+
access: 'open'
|
103
|
+
}.merge(opts) if opts
|
104
|
+
|
105
|
+
url = "#{RubyBox::API_URL}/#{resource_name}/#{id}"
|
106
|
+
uri = URI.parse(url)
|
107
|
+
|
108
|
+
request = Net::HTTP::Put.new(uri.path, {
|
109
|
+
"Content-Type" => 'application/json'
|
110
|
+
})
|
111
|
+
|
112
|
+
request.body = JSON.dump({
|
113
|
+
shared_link: opts
|
114
|
+
})
|
115
|
+
|
116
|
+
@raw_item = @session.request(uri, request)
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
def disable_shared_link(opts={})
|
121
|
+
create_shared_link(nil)
|
122
|
+
end
|
123
|
+
|
124
|
+
def shared_link
|
125
|
+
return nil unless @raw_item['shared_link']
|
126
|
+
RubyBox::Item.factory(@session, @raw_item['shared_link'].merge('type' => 'shared_link'))
|
127
|
+
end
|
128
|
+
|
129
|
+
def as_json(opts={})
|
130
|
+
@raw_item
|
131
|
+
end
|
132
|
+
|
133
|
+
protected
|
134
|
+
|
135
|
+
def self.factory(session, entry)
|
136
|
+
type = entry['type'] ? entry['type'].split('_').map(&:capitalize).join('').to_sym : nil
|
137
|
+
if RubyBox.constants.include? type
|
138
|
+
RubyBox.const_get(type).new(session, entry)
|
139
|
+
else
|
140
|
+
RubyBox::Item.new(session, entry)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def has_mini_format?
|
145
|
+
false
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
def many(key)
|
151
|
+
url = "#{RubyBox::API_URL}/#{resource_name}/#{id}/#{key}"
|
152
|
+
resp = @session.get( url )
|
153
|
+
resp['entries'].map {|i| RubyBox::Item.factory(@session, i)}
|
154
|
+
end
|
155
|
+
|
156
|
+
def paginated(key, item_limit=100, offset=0, fields=nil)
|
157
|
+
Enumerator.new do |yielder|
|
158
|
+
while true
|
159
|
+
url = "#{RubyBox::API_URL}/#{resource_name}/#{id}/#{key}?limit=#{item_limit}&offset=#{offset}"
|
160
|
+
url = "#{url}&fields=#{fields.map(&:to_s).join(',')}" if fields
|
161
|
+
resp = @session.get( url )
|
162
|
+
resp['entries'].each do |entry|
|
163
|
+
yielder.yield(RubyBox::Item.factory(@session, entry))
|
164
|
+
end
|
165
|
+
offset += resp['entries'].count
|
166
|
+
break if resp['offset'].to_i + resp['limit'].to_i >= resp['total_count'].to_i
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def serialize
|
172
|
+
update_fields.inject({}) {|hash, field| hash[field] = @raw_item[field]; hash}
|
173
|
+
end
|
174
|
+
|
175
|
+
def update_fields
|
176
|
+
['name', 'description', 'parent']
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module RubyBox
|
4
|
+
class Session
|
5
|
+
|
6
|
+
OAUTH2_URLS = {
|
7
|
+
:site => 'https://www.box.com',
|
8
|
+
:authorize_url => "/api/oauth2/authorize",
|
9
|
+
:token_url => "/api/oauth2/token"
|
10
|
+
}
|
11
|
+
|
12
|
+
def initialize(opts={}, backoff=0.1)
|
13
|
+
|
14
|
+
@backoff = backoff # try not to excessively hammer API.
|
15
|
+
|
16
|
+
if opts[:client_id]
|
17
|
+
@oauth2_client = OAuth2::Client.new(opts[:client_id], opts[:client_secret], OAUTH2_URLS.dup)
|
18
|
+
@access_token = OAuth2::AccessToken.new(@oauth2_client, opts[:access_token]) if opts[:access_token]
|
19
|
+
@refresh_token = opts[:refresh_token]
|
20
|
+
@as_user = opts[:as_user]
|
21
|
+
else # Support legacy API for historical reasons.
|
22
|
+
@api_key = opts[:api_key]
|
23
|
+
@auth_token = opts[:auth_token]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def authorize_url(redirect_uri, state=nil)
|
28
|
+
opts = { :redirect_uri => redirect_uri }
|
29
|
+
opts[:state] = state if state
|
30
|
+
|
31
|
+
@oauth2_client.auth_code.authorize_url(opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_access_token(code)
|
35
|
+
@access_token = @oauth2_client.auth_code.get_token(code)
|
36
|
+
end
|
37
|
+
|
38
|
+
def refresh_token(refresh_token)
|
39
|
+
refresh_access_token_obj = OAuth2::AccessToken.new(@oauth2_client, @access_token.token, {'refresh_token' => refresh_token})
|
40
|
+
@access_token = refresh_access_token_obj.refresh!
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_auth_header
|
44
|
+
"BoxAuth api_key=#{@api_key}&auth_token=#{@auth_token}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def get(url, raw=false)
|
48
|
+
uri = URI.parse(url)
|
49
|
+
request = Net::HTTP::Get.new( uri.request_uri )
|
50
|
+
resp = request( uri, request, raw )
|
51
|
+
end
|
52
|
+
|
53
|
+
def delete(url, raw=false)
|
54
|
+
uri = URI.parse(url)
|
55
|
+
request = Net::HTTP::Delete.new( uri.request_uri )
|
56
|
+
resp = request( uri, request, raw )
|
57
|
+
end
|
58
|
+
|
59
|
+
def request(uri, request, raw=false, retries=0)
|
60
|
+
|
61
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
62
|
+
http.use_ssl = true
|
63
|
+
http.ssl_version = :SSLv3
|
64
|
+
#http.set_debug_output($stdout)
|
65
|
+
|
66
|
+
if @access_token
|
67
|
+
request.add_field('Authorization', "Bearer #{@access_token.token}")
|
68
|
+
else
|
69
|
+
request.add_field('Authorization', build_auth_header)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
request.add_field('As-User', "#{@as_user}") if @as_user
|
74
|
+
|
75
|
+
response = http.request(request)
|
76
|
+
|
77
|
+
if response.is_a? Net::HTTPNotFound
|
78
|
+
raise RubyBox::ObjectNotFound
|
79
|
+
end
|
80
|
+
|
81
|
+
# Got unauthorized (401) status, try to refresh the token
|
82
|
+
if response.code.to_i == 401 and @refresh_token and retries == 0
|
83
|
+
refresh_token(@refresh_token)
|
84
|
+
return request(uri, request, raw, retries + 1)
|
85
|
+
end
|
86
|
+
|
87
|
+
sleep(@backoff) # try not to excessively hammer API.
|
88
|
+
|
89
|
+
handle_errors( response, raw )
|
90
|
+
end
|
91
|
+
|
92
|
+
def do_stream(url, opts)
|
93
|
+
params = {
|
94
|
+
:content_length_proc => opts[:content_length_proc],
|
95
|
+
:progress_proc => opts[:progress_proc]
|
96
|
+
}
|
97
|
+
|
98
|
+
if @access_token
|
99
|
+
params['Authorization'] = "Bearer #{@access_token.token}"
|
100
|
+
else
|
101
|
+
params['Authorization'] = build_auth_header
|
102
|
+
end
|
103
|
+
|
104
|
+
params['As-User'] = @as_user if @as_user
|
105
|
+
|
106
|
+
open(url, params)
|
107
|
+
end
|
108
|
+
|
109
|
+
def handle_errors( response, raw )
|
110
|
+
status = response.code.to_i
|
111
|
+
body = response.body
|
112
|
+
begin
|
113
|
+
parsed_body = JSON.parse(body)
|
114
|
+
rescue
|
115
|
+
msg = body.nil? || body.empty? ? "no data returned" : body
|
116
|
+
parsed_body = { "message" => msg }
|
117
|
+
end
|
118
|
+
|
119
|
+
# status is used to determine whether
|
120
|
+
# we need to refresh the access token.
|
121
|
+
parsed_body["status"] = status
|
122
|
+
|
123
|
+
case status / 100
|
124
|
+
when 3
|
125
|
+
# 302 Found. We should return the url
|
126
|
+
parsed_body["location"] = response["Location"] if status == 302
|
127
|
+
when 4
|
128
|
+
raise(RubyBox::ItemNameInUse.new(parsed_body, status, body), parsed_body["message"]) if parsed_body["code"] == "item_name_in_use"
|
129
|
+
raise(RubyBox::AuthError.new(parsed_body, status, body), parsed_body["message"]) if parsed_body["code"] == "unauthorized" || status == 401
|
130
|
+
raise(RubyBox::RequestError.new(parsed_body, status, body), parsed_body["message"])
|
131
|
+
when 5
|
132
|
+
raise(RubyBox::ServerError.new(parsed_body, status, body), parsed_body["message"])
|
133
|
+
end
|
134
|
+
raw ? body : parsed_body
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "lti-ruby-box"
|
8
|
+
s.version = "1.14.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Attachments.me", "wbhumphrey"]
|
12
|
+
s.date = "2014-04-08"
|
13
|
+
s.description = "ruby gem for box.com 2.0 api"
|
14
|
+
s.email = "brad@instructure.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".travis.yml",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README.markdown",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"lib/ruby-box.rb",
|
29
|
+
"lib/ruby-box/client.rb",
|
30
|
+
"lib/ruby-box/collaboration.rb",
|
31
|
+
"lib/ruby-box/comment.rb",
|
32
|
+
"lib/ruby-box/discussion.rb",
|
33
|
+
"lib/ruby-box/event.rb",
|
34
|
+
"lib/ruby-box/event_response.rb",
|
35
|
+
"lib/ruby-box/exceptions.rb",
|
36
|
+
"lib/ruby-box/file.rb",
|
37
|
+
"lib/ruby-box/folder.rb",
|
38
|
+
"lib/ruby-box/item.rb",
|
39
|
+
"lib/ruby-box/session.rb",
|
40
|
+
"lib/ruby-box/shared_link.rb",
|
41
|
+
"lib/ruby-box/user.rb",
|
42
|
+
"lib/ruby-box/web_link.rb",
|
43
|
+
"lib/ruby-box/login_token.rb",
|
44
|
+
"lti-ruby-box.gemspec",
|
45
|
+
# "spec/client_spec.rb",
|
46
|
+
# "spec/event_spec.rb",
|
47
|
+
# "spec/file_spec.rb",
|
48
|
+
# "spec/fixtures/comment_create.json",
|
49
|
+
# "spec/fixtures/events.json",
|
50
|
+
# "spec/fixtures/me.json",
|
51
|
+
# "spec/fixtures/users.json",
|
52
|
+
# "spec/folder_spec.rb",
|
53
|
+
# "spec/helper/account.example",
|
54
|
+
# "spec/helper/account.rb",
|
55
|
+
# "spec/integration_spec.rb",
|
56
|
+
# "spec/item_spec.rb",
|
57
|
+
# "spec/me_spec.rb",
|
58
|
+
# "spec/session_spec.rb",
|
59
|
+
# "spec/spec_helper.rb",
|
60
|
+
# "spec/users_spec.rb"
|
61
|
+
]
|
62
|
+
s.homepage = "https://github.com/wbhumphrey/ruby-box"
|
63
|
+
s.licenses = ["MIT"]
|
64
|
+
s.require_paths = ["lib"]
|
65
|
+
s.rubygems_version = "2.0.3"
|
66
|
+
s.summary = "ruby gem for box.com 2.0 api"
|
67
|
+
|
68
|
+
if s.respond_to? :specification_version then
|
69
|
+
s.specification_version = 4
|
70
|
+
|
71
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
72
|
+
s.add_runtime_dependency(%q<multipart-post>, [">= 0"])
|
73
|
+
s.add_runtime_dependency(%q<oauth2>, [">= 0"])
|
74
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
75
|
+
s.add_runtime_dependency(%q<addressable>, [">= 0"])
|
76
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
77
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
78
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
79
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
80
|
+
else
|
81
|
+
s.add_dependency(%q<multipart-post>, [">= 0"])
|
82
|
+
s.add_dependency(%q<oauth2>, [">= 0"])
|
83
|
+
s.add_dependency(%q<json>, [">= 0"])
|
84
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
85
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
86
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
87
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
88
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
89
|
+
end
|
90
|
+
else
|
91
|
+
s.add_dependency(%q<multipart-post>, [">= 0"])
|
92
|
+
s.add_dependency(%q<oauth2>, [">= 0"])
|
93
|
+
s.add_dependency(%q<json>, [">= 0"])
|
94
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
95
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
96
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
97
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
98
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|