basecamp 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: