basecamp 0.0.9 → 0.0.10

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6a4aed33709e1c506d03f74ea93caa37b20e28f6
4
+ data.tar.gz: 724ac3904f5e834266ab001891f7bc270fe358f4
5
+ SHA512:
6
+ metadata.gz: 38d4ff046a943c7e16ca6852cd14ba098505b7ef5a7c1d6a1924433c98dc116b2d9811a398ee3e3b9106220e023251e1d10284864ccb06d82ebbab394440295e
7
+ data.tar.gz: c795d56445d90fadb6937d3f102ecae247fa4dc0e841f94515070fd64f6ed47d002c027ccd9512a204ae944c4afcf63b0e74e90545234b947f69c162ba8497ea
@@ -43,10 +43,16 @@ requires your Basecamp site address and your login credentials or API token.
43
43
 
44
44
  Basecamp.establish_connection!('yoururl.basecamphq.com', 'APITOKEN', 'X')
45
45
 
46
+ === Using OAuth access token
47
+
48
+ Basecamp.establish_oauth_connection!('yoururl.basecamphq.com', 'oauth_access_token')
49
+
46
50
  === With a Basecamp account that use SSL (https://yoururl.basecamphq.com)
47
51
 
48
52
  Basecamp.establish_connection!('yoururl.basecamphq.com', 'APITOKEN', 'X', true)
49
53
 
54
+ Basecamp.establish_oauth_connection!('yoururl.basecamphq.com', 'oauth_access_token', true)
55
+
50
56
  This is the same whether you're accessing using the ActiveResource interface,
51
57
  or the legacy interface.
52
58
 
@@ -59,6 +65,22 @@ information on working with ActiveResource, see:
59
65
  * http://api.rubyonrails.org/files/activeresource/README.html
60
66
  * http://api.rubyonrails.org/classes/ActiveResource/Base.html
61
67
 
68
+ == Basecamp API rate limit and app identification
69
+
70
+ If your app creates a lot of requests, you may hit the (new) basecamp rate limit. ({read more here about rate limiting}[https://github.com/basecamp/basecamp-classic-api#rate-limiting]).
71
+
72
+ To raise your limit you can send a custom user-agent to basecamp with your identifying information ({read more here}[https://github.com/basecamp/basecamp-classic-api#rate-limiting]).
73
+
74
+ For this you need to create an initializer in your rails application, for example: +config/inititalizer/basecamp_user_agent.rb+ with the following line:
75
+
76
+ ActiveResource::Base.headers["User-Agent"] = "Fabian's Ingenious Integration (fabian@example.com)"
77
+
78
+ This initializer ensures that all requests made through ActiveResource (which this gem uses) are identifiable with your information.
79
+
80
+ **NOTE**: If you are using ActiveResource for accessing multiple APIs at once and not only basecamp's, you will need the following initializer instead:
81
+
82
+ Basecamp::Resource.headers["User-Agent"] = "Fabian's Ingenious Integration (fabian@example.com)"
83
+
62
84
  === Finding a Resource
63
85
 
64
86
  Find a specific resource using the +find+ method. Attributes of the resource
@@ -196,6 +218,40 @@ By default the wrapper will use :xml for the active record connection but you ca
196
218
 
197
219
  Note: We recommend using xml. There are some API calls that don't behave well with json.
198
220
 
221
+ = Access active resource response object
222
+
223
+ You can acces the last response object:
224
+
225
+ Basecamp::Message.find(:all, params => { :project_id => 1037 })
226
+ Basecamp::Message.connection.response["status"] # => "200 OK"
227
+
228
+ = Using the raw response body
229
+
230
+ This is useful for example to get pagination data to access all comments in a commentable resource: https://github.com/37signals/basecamp-classic-api/blob/master/sections/comments.md#get-recent-comments-for-a-commentable-resource
231
+
232
+ def get_threshold
233
+ # Get the last response object
234
+ response = Basecamp::Comment.connection.response
235
+ # Parse the xml
236
+ xml = XmlSimple.xml_in(response.body)
237
+ # continued-at is an attribute specifying the path where the next oldest 75 comments can be retrieved
238
+ if continued_at = xml["continued-at"]
239
+ # There are more comments
240
+ # We need to extract the threshold parameter from the continued-at url
241
+ hash = CGI::parse(URI.parse(continued_at).query)
242
+ hash["threshold"].first
243
+ else
244
+ # We're done
245
+ nil
246
+ end
247
+ end
248
+
249
+ comments = Basecamp::Comment.find(:all, :params => { :post_id => 1037 })
250
+ if threshold = get_threshold
251
+ # Get the next set of comments using the threshold
252
+ Basecamp::Comment.find(:all, :params => { :post_id => 1037, :threshold => threshold })
253
+ end
254
+
199
255
  == Contributors
200
256
 
201
257
  * jamesarosen
@@ -7,6 +7,7 @@ require 'xmlsimple'
7
7
 
8
8
  require 'basecamp/base'
9
9
  require 'basecamp/connection'
10
+ require 'basecamp/active_resource'
10
11
  require 'basecamp/hash'
11
12
  require 'basecamp/record'
12
13
  require 'basecamp/resource'
@@ -0,0 +1,23 @@
1
+ # ActiveResource connection patch to let users access the last response object and the headers.
2
+ #
3
+ # Example:
4
+ # >> Basecamp::Message.find(:all, params => { :project_id => 1037 })
5
+ # >> Basecamp::Message.connection.response["status"]
6
+ # => "200 OK"
7
+ class ActiveResource::Connection
8
+ alias_method :original_handle_response, :handle_response
9
+ alias :static_default_header :default_header
10
+
11
+ def handle_response(response)
12
+ Thread.current[:active_resource_connection_headers] = response
13
+ original_handle_response(response)
14
+ end
15
+
16
+ def response
17
+ Thread.current[:active_resource_connection_headers]
18
+ end
19
+
20
+ def set_header(key, value)
21
+ default_header.update(key => value)
22
+ end
23
+ end
@@ -1,14 +1,15 @@
1
1
  module Basecamp
2
2
  class << self
3
3
  attr_accessor :use_xml
4
- attr_reader :site, :user, :password, :use_ssl
4
+ attr_reader :site, :user, :password, :use_ssl, :use_oauth, :access_token
5
5
 
6
6
  def establish_connection!(site, user, password, use_ssl = false, use_xml = true)
7
- @site = site
8
- @user = user
9
- @password = password
10
- @use_ssl = use_ssl
11
- @use_xml = use_xml
7
+ @site = site
8
+ @user = user
9
+ @password = password
10
+ @use_ssl = use_ssl
11
+ @use_xml = use_xml
12
+ @use_oauth = false
12
13
 
13
14
  Resource.user = user
14
15
  Resource.password = password
@@ -18,6 +19,20 @@ module Basecamp
18
19
  @connection = Connection.new(self)
19
20
  end
20
21
 
22
+ def establish_oauth_connection!(site, access_token, use_ssl = false, use_xml = true)
23
+ @site = site
24
+ @use_ssl = use_ssl
25
+ @use_xml = use_xml
26
+ @use_oauth = true
27
+ @access_token = access_token
28
+
29
+ Resource.site = (use_ssl ? "https" : "http") + "://" + site
30
+ Resource.format = (use_xml ? :xml : :json)
31
+ Resource.connection.set_header('Authorization', "Bearer #{access_token}")
32
+
33
+ @connection = Connection.new(self)
34
+ end
35
+
21
36
  def connection
22
37
  @connection || raise('No connection established')
23
38
  end
@@ -25,9 +40,16 @@ module Basecamp
25
40
  # Make a raw web-service request to Basecamp. This will return a Hash of
26
41
  # Arrays of the response, and may seem a little odd to the uninitiated.
27
42
  def request(path, parameters = {})
28
- response = Basecamp.connection.post(path, StringIO.new(convert_body(parameters)), "Content-Type" => content_type)
43
+ headers = { "Content-Type" => content_type }
44
+ headers.merge!('Authorization' => "Bearer #{@access_token}") if @use_oauth
45
+ if parameters.empty?
46
+ response = Basecamp.connection.get(path, headers)
47
+ else
48
+ response = Basecamp.connection.post(path, StringIO.new(convert_body(parameters)), headers)
49
+ end
29
50
 
30
51
  if response.code.to_i / 100 == 2
52
+ return {} if response.body.blank?
31
53
  result = XmlSimple.xml_in(response.body, 'keeproot' => true, 'contentkey' => '__content__', 'forcecontent' => true)
32
54
  typecast_value(result)
33
55
  else
@@ -8,7 +8,8 @@ module Basecamp; class Connection
8
8
 
9
9
  def post(path, iostream, headers = {})
10
10
  request = Net::HTTP::Post.new(path, headers.merge('Accept' => 'application/xml'))
11
- request.basic_auth(@master.user, @master.password)
11
+ request.basic_auth(@master.user, @master.password) unless @master.use_oauth
12
+ request.initialize_http_header(@master.class.headers)
12
13
  request.body_stream = iostream
13
14
  request.content_length = iostream.size
14
15
  @connection.request(request)
@@ -16,7 +17,8 @@ module Basecamp; class Connection
16
17
 
17
18
  def get(path, headers = {})
18
19
  request = Net::HTTP::Get.new(path, headers.merge('Accept' => 'application/xml'))
19
- request.basic_auth(@master.user, @master.password)
20
+ request.initialize_http_header(@master.class.headers)
21
+ request.basic_auth(@master.user, @master.password) unless @master.use_oauth
20
22
  @connection.request(request)
21
23
  end
22
24
  end; end
@@ -1,5 +1,5 @@
1
1
  module Basecamp; class TimeEntry < Basecamp::Resource
2
- parent_resources :project, :todo_item
2
+ parent_resources :project
3
3
 
4
4
  def self.all(project_id, page = 0)
5
5
  find(:all, :params => { :project_id => project_id, :page => page })
@@ -1,6 +1,4 @@
1
1
  module Basecamp; class TodoItem < Basecamp::Resource
2
- parent_resources :todo_list
3
-
4
2
  def todo_list(options = {})
5
3
  @todo_list ||= TodoList.find(todo_list_id, options)
6
4
  end
metadata CHANGED
@@ -1,139 +1,123 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: basecamp
3
- version: !ruby/object:Gem::Version
4
- hash: 13
5
- prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 9
10
- version: 0.0.9
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.10
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Anibal Cucco
14
8
  - James A. Rosen
15
9
  autorequire:
16
10
  bindir: bin
17
11
  cert_chain: []
18
-
19
- date: 2012-01-27 00:00:00 -03:00
20
- default_executable:
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
12
+ date: 2014-11-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
23
15
  name: oauth2
24
- prerelease: false
25
- requirement: &id001 !ruby/object:Gem::Requirement
26
- none: false
27
- requirements:
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
28
18
  - - ">="
29
- - !ruby/object:Gem::Version
30
- hash: 3
31
- segments:
32
- - 0
33
- version: "0"
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
34
21
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: xml-simple
38
22
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: xml-simple
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
42
32
  - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 3
45
- segments:
46
- - 0
47
- version: "0"
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
48
35
  type: :runtime
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: activeresource
52
36
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: activeresource
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
56
46
  - - ">="
57
- - !ruby/object:Gem::Version
58
- hash: 3
59
- segments:
60
- - 2
61
- - 3
62
- - 0
47
+ - !ruby/object:Gem::Version
63
48
  version: 2.3.0
64
49
  type: :runtime
65
- version_requirements: *id003
66
- - !ruby/object:Gem::Dependency
67
- name: rake
68
50
  prerelease: false
69
- requirement: &id004 !ruby/object:Gem::Requirement
70
- none: false
71
- requirements:
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
72
53
  - - ">="
73
- - !ruby/object:Gem::Version
74
- hash: 3
75
- segments:
76
- - 0
77
- version: "0"
54
+ - !ruby/object:Gem::Version
55
+ version: 2.3.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: rake
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
78
63
  type: :development
79
- version_requirements: *id004
80
- - !ruby/object:Gem::Dependency
81
- name: mg
82
64
  prerelease: false
83
- requirement: &id005 !ruby/object:Gem::Requirement
84
- none: false
85
- requirements:
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
86
67
  - - ">="
87
- - !ruby/object:Gem::Version
88
- hash: 15
89
- segments:
90
- - 0
91
- - 0
92
- - 8
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: mg
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
93
76
  version: 0.0.8
94
77
  type: :development
95
- version_requirements: *id005
96
- - !ruby/object:Gem::Dependency
97
- name: rspec
98
78
  prerelease: false
99
- requirement: &id006 !ruby/object:Gem::Requirement
100
- none: false
101
- requirements:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
102
81
  - - ">="
103
- - !ruby/object:Gem::Version
104
- hash: 27
105
- segments:
106
- - 1
107
- - 3
108
- - 0
82
+ - !ruby/object:Gem::Version
83
+ version: 0.0.8
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
109
90
  version: 1.3.0
110
91
  type: :development
111
- version_requirements: *id006
112
- - !ruby/object:Gem::Dependency
113
- name: webmock
114
92
  prerelease: false
115
- requirement: &id007 !ruby/object:Gem::Requirement
116
- none: false
117
- requirements:
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 1.3.0
98
+ - !ruby/object:Gem::Dependency
99
+ name: webmock
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
118
102
  - - ">="
119
- - !ruby/object:Gem::Version
120
- hash: 27
121
- segments:
122
- - 1
123
- - 2
124
- - 2
103
+ - !ruby/object:Gem::Version
125
104
  version: 1.2.2
126
105
  type: :development
127
- version_requirements: *id007
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 1.2.2
128
112
  description: Basecamp API wrapper.
129
113
  email: nobody@gmail.com
130
114
  executables: []
131
-
132
115
  extensions: []
133
-
134
116
  extra_rdoc_files: []
135
-
136
- files:
117
+ files:
118
+ - README.rdoc
119
+ - lib/basecamp.rb
120
+ - lib/basecamp/active_resource.rb
137
121
  - lib/basecamp/base.rb
138
122
  - lib/basecamp/connection.rb
139
123
  - lib/basecamp/hash.rb
@@ -151,41 +135,28 @@ files:
151
135
  - lib/basecamp/resources/todo_item.rb
152
136
  - lib/basecamp/resources/todo_list.rb
153
137
  - lib/basecamp/symbol.rb
154
- - lib/basecamp.rb
155
- - README.rdoc
156
- has_rdoc: true
157
138
  homepage: http://github.com/anibalcucco/basecamp-wrapper
158
139
  licenses: []
159
-
140
+ metadata: {}
160
141
  post_install_message:
161
142
  rdoc_options: []
162
-
163
- require_paths:
143
+ require_paths:
164
144
  - lib
165
- required_ruby_version: !ruby/object:Gem::Requirement
166
- none: false
167
- requirements:
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ requirements:
168
147
  - - ">="
169
- - !ruby/object:Gem::Version
170
- hash: 3
171
- segments:
172
- - 0
173
- version: "0"
174
- required_rubygems_version: !ruby/object:Gem::Requirement
175
- none: false
176
- requirements:
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
151
+ requirements:
177
152
  - - ">="
178
- - !ruby/object:Gem::Version
179
- hash: 3
180
- segments:
181
- - 0
182
- version: "0"
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
183
155
  requirements: []
184
-
185
156
  rubyforge_project:
186
- rubygems_version: 1.5.3
157
+ rubygems_version: 2.4.2
187
158
  signing_key:
188
- specification_version: 3
159
+ specification_version: 4
189
160
  summary: Basecamp API wrapper.
190
161
  test_files: []
191
-
162
+ has_rdoc: