lti-ruby-box 1.14.1

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.
@@ -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,9 @@
1
+ module RubyBox
2
+ class LoginToken < Item
3
+
4
+ def resource_name
5
+ 'login_tokens'
6
+ end
7
+
8
+ end
9
+ 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,10 @@
1
+ module RubyBox
2
+ class SharedLink < Item
3
+
4
+ private
5
+
6
+ def has_mini_format?
7
+ false
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ module RubyBox
2
+ class User < Item
3
+
4
+ def enterprise
5
+ resp = @session.get( "#{RubyBox::API_URL}/users/#{id}?fields=enterprise" )
6
+ resp["enterprise"]
7
+ end
8
+
9
+ private
10
+
11
+ def resource_name
12
+ 'users'
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ module RubyBox
2
+ class WebLink < Item
3
+ end
4
+ 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
+