iora-ruby-box 1.14.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.
@@ -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,136 @@
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.set_debug_output($stdout)
64
+
65
+ if @access_token
66
+ request.add_field('Authorization', "Bearer #{@access_token.token}")
67
+ else
68
+ request.add_field('Authorization', build_auth_header)
69
+ end
70
+
71
+
72
+ request.add_field('As-User', "#{@as_user}") if @as_user
73
+
74
+ response = http.request(request)
75
+
76
+ if response.is_a? Net::HTTPNotFound
77
+ raise RubyBox::ObjectNotFound
78
+ end
79
+
80
+ # Got unauthorized (401) status, try to refresh the token
81
+ if response.code.to_i == 401 and @refresh_token and retries == 0
82
+ refresh_token(@refresh_token)
83
+ return request(uri, request, raw, retries + 1)
84
+ end
85
+
86
+ sleep(@backoff) # try not to excessively hammer API.
87
+
88
+ handle_errors( response, raw )
89
+ end
90
+
91
+ def do_stream(url, opts)
92
+ params = {
93
+ :content_length_proc => opts[:content_length_proc],
94
+ :progress_proc => opts[:progress_proc]
95
+ }
96
+
97
+ if @access_token
98
+ params['Authorization'] = "Bearer #{@access_token.token}"
99
+ else
100
+ params['Authorization'] = build_auth_header
101
+ end
102
+
103
+ params['As-User'] = @as_user if @as_user
104
+
105
+ open(url, params)
106
+ end
107
+
108
+ def handle_errors( response, raw )
109
+ status = response.code.to_i
110
+ body = response.body
111
+ begin
112
+ parsed_body = JSON.parse(body)
113
+ rescue
114
+ msg = body.nil? || body.empty? ? "no data returned" : body
115
+ parsed_body = { "message" => msg }
116
+ end
117
+
118
+ # status is used to determine whether
119
+ # we need to refresh the access token.
120
+ parsed_body["status"] = status
121
+
122
+ case status / 100
123
+ when 3
124
+ # 302 Found. We should return the url
125
+ parsed_body["location"] = response["Location"] if status == 302
126
+ when 4
127
+ raise(RubyBox::ItemNameInUse.new(parsed_body, status, body), parsed_body["message"]) if parsed_body["code"] == "item_name_in_use"
128
+ raise(RubyBox::AuthError.new(parsed_body, status, body), parsed_body["message"]) if parsed_body["code"] == "unauthorized" || status == 401
129
+ raise(RubyBox::RequestError.new(parsed_body, status, body), parsed_body["message"])
130
+ when 5
131
+ raise(RubyBox::ServerError.new(parsed_body, status, body), parsed_body["message"])
132
+ end
133
+ raw ? body : parsed_body
134
+ end
135
+ end
136
+ 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
data/ruby-box.gemspec ADDED
@@ -0,0 +1,99 @@
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
+ # stub: ruby-box 1.14.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "iora-ruby-box"
9
+ s.version = "1.14.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib"]
13
+ s.authors = ["Patrick Robertson"]
14
+ s.date = "2014-03-07"
15
+ s.description = "ruby gem for box.com 2.0 api"
16
+ s.email = "patricksrobertson@gmail.com"
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.markdown"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".travis.yml",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE.txt",
27
+ "README.markdown",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "lib/ruby-box.rb",
31
+ "lib/ruby-box/client.rb",
32
+ "lib/ruby-box/collaboration.rb",
33
+ "lib/ruby-box/comment.rb",
34
+ "lib/ruby-box/discussion.rb",
35
+ "lib/ruby-box/event.rb",
36
+ "lib/ruby-box/event_response.rb",
37
+ "lib/ruby-box/exceptions.rb",
38
+ "lib/ruby-box/file.rb",
39
+ "lib/ruby-box/folder.rb",
40
+ "lib/ruby-box/item.rb",
41
+ "lib/ruby-box/session.rb",
42
+ "lib/ruby-box/shared_link.rb",
43
+ "lib/ruby-box/user.rb",
44
+ "lib/ruby-box/web_link.rb",
45
+ "ruby-box.gemspec",
46
+ "spec/client_spec.rb",
47
+ "spec/event_spec.rb",
48
+ "spec/file_spec.rb",
49
+ "spec/fixtures/comment_create.json",
50
+ "spec/fixtures/events.json",
51
+ "spec/fixtures/me.json",
52
+ "spec/fixtures/users.json",
53
+ "spec/folder_spec.rb",
54
+ "spec/helper/account.example",
55
+ "spec/helper/account.rb",
56
+ "spec/integration_spec.rb",
57
+ "spec/item_spec.rb",
58
+ "spec/me_spec.rb",
59
+ "spec/spec_helper.rb",
60
+ "spec/users_spec.rb"
61
+ ]
62
+ s.homepage = "http://github.com/attachmentsme/ruby-box"
63
+ s.licenses = ["MIT"]
64
+ s.rubygems_version = "2.2.1"
65
+ s.summary = "ruby gem for box.com 2.0 api"
66
+
67
+ if s.respond_to? :specification_version then
68
+ s.specification_version = 4
69
+
70
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
71
+ s.add_runtime_dependency(%q<multipart-post>, [">= 0"])
72
+ s.add_runtime_dependency(%q<oauth2>, [">= 0"])
73
+ s.add_runtime_dependency(%q<json>, [">= 0"])
74
+ s.add_runtime_dependency(%q<addressable>, [">= 0"])
75
+ s.add_development_dependency(%q<rspec>, [">= 0"])
76
+ s.add_development_dependency(%q<bundler>, [">= 0"])
77
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
78
+ s.add_development_dependency(%q<webmock>, [">= 0"])
79
+ else
80
+ s.add_dependency(%q<multipart-post>, [">= 0"])
81
+ s.add_dependency(%q<oauth2>, [">= 0"])
82
+ s.add_dependency(%q<json>, [">= 0"])
83
+ s.add_dependency(%q<addressable>, [">= 0"])
84
+ s.add_dependency(%q<rspec>, [">= 0"])
85
+ s.add_dependency(%q<bundler>, [">= 0"])
86
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
87
+ s.add_dependency(%q<webmock>, [">= 0"])
88
+ end
89
+ else
90
+ s.add_dependency(%q<multipart-post>, [">= 0"])
91
+ s.add_dependency(%q<oauth2>, [">= 0"])
92
+ s.add_dependency(%q<json>, [">= 0"])
93
+ s.add_dependency(%q<addressable>, [">= 0"])
94
+ s.add_dependency(%q<rspec>, [">= 0"])
95
+ s.add_dependency(%q<bundler>, [">= 0"])
96
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
97
+ s.add_dependency(%q<webmock>, [">= 0"])
98
+ end
99
+ end