eventfulapi 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README +2 -3
  2. data/lib/eventful/api.rb +178 -91
  3. metadata +4 -4
data/README CHANGED
@@ -5,6 +5,5 @@ calendars, and users.
5
5
  See http://api.eventful.com/ for general information about the API, and
6
6
  http://api.eventful.com/docs/libs/ruby/doc for documentation about the Ruby library.
7
7
 
8
- Copyright 2005-2007 EVDB, Inc. All rights reserved. This module is distributed
9
- under the same terms as Ruby itself (see
10
- http://www.ruby-lang.org/en/LICENSE.txt)
8
+ Copyright 2005-2007 EVDB, Inc. This module is distributed under the same terms
9
+ as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt)
@@ -13,36 +13,89 @@
13
13
  # begin
14
14
  #
15
15
  # # Start an API session with a username and password
16
- # eventful = Eventful::API.new 'application_key',
17
- # 'user' => 'username',
18
- # 'password' => 'password'
16
+ # eventful = Eventful::API.new 'application_key',
17
+ # :user => 'username',
18
+ # :password => 'password'
19
19
  #
20
20
  # # Lookup an event by its unique id
21
21
  # event = eventful.call 'events/get',
22
- # 'id' => 'E0-001-001042544-7'
22
+ # :id => 'E0-001-001042544-7'
23
23
  #
24
24
  # puts "Event Title: #{event['title']}"
25
- #
25
+ #
26
26
  # # Get information about that event's venue
27
- # venue = eventful.call 'venues/get',
28
- # 'id' => event['venue_id']
27
+ # venue = eventful.call 'venues/get',
28
+ # :id => event['venue_id']
29
29
  #
30
30
  # puts "Venue: #{venue['name']}"
31
31
  #
32
32
  # rescue Eventful::APIError => e
33
- # puts "There was an error fetching the event: #{e}"
33
+ # puts "There was a problem with the API: #{e}"
34
+ # end
35
+ #
36
+ #
37
+ # == Another Example
38
+ #
39
+ # require 'rubygems'
40
+ # require 'eventful/api'
41
+ #
42
+ # # First, create our Eventful::API object
43
+ # eventful = Eventful::API.new 'application_key'
44
+ #
45
+ # loop do
46
+ # # Ask the user what and where to search
47
+ # puts "Search where? (Ex: San Diego)"
48
+ # print "? "
49
+ # location = gets.chomp
50
+ # puts "Search for what (Ex: music)"
51
+ # print "? "
52
+ # query = gets.chomp
53
+ #
54
+ # # This is the cool part!
55
+ # results = eventful.call 'events/search',
56
+ # :keywords => query,
57
+ # :location => location,
58
+ # :page_size => 5
59
+ #
60
+ # # If we couldn't find anything, ask the user again
61
+ # if results['events'].nil? then
62
+ # puts
63
+ # puts "Hmm. I couldn't find anything. Sorry."
64
+ # puts
65
+ # next
66
+ # end
67
+ #
68
+ # # Output the results
69
+ # results['events']['event'].each do |event|
70
+ # puts
71
+ # puts "http://eventful.com/events/" + event['id']
72
+ # puts event['title']
73
+ # puts " at " + event['venue_name']
74
+ # puts " on " + Time.parse(event['start_time']).strftime("%a, %b %d, %I:%M %p") if event['start_time']
75
+ # end
76
+ # puts
34
77
  # end
35
78
  #
36
79
  #
37
80
  # == API Key
38
81
  #
39
- # Use of the Eventful API requires an application key
82
+ # Use of the Eventful API requires an application key
40
83
  # (see http://api.eventful.com/keys for more information).
41
84
  #
42
85
  # == Change Notes
43
86
  #
44
87
  # === Eventful API
45
88
  #
89
+ # ==== Version 2.2.0
90
+ #
91
+ # - The authentication bug has been fixed, so I'm rolling back the workaround.
92
+ # - Documented the parameters for specifying alternative API servers when calling
93
+ # Eventful.new
94
+ # - The names of these keys have been changed to be a bit friendlier. The old
95
+ # keys will still work fine.
96
+ # - Hash keys to methods can now be Symbols, in addition to strings
97
+ # - A fun new example, just because
98
+ #
46
99
  # ==== Version 2.1.1
47
100
  #
48
101
  # - Includes a workaround fix for an authentication bug. This fix may be rolled
@@ -50,10 +103,10 @@
50
103
  #
51
104
  # ==== Version 2.1
52
105
  #
53
- # - As EVDB Inc. has been renamed Eventful Inc., the EVDB module has been
54
- # renamed Eventful, and the gem is now named eventfulapi. Support for the
106
+ # - As EVDB Inc. has been renamed Eventful Inc., the EVDB module has been
107
+ # renamed Eventful, and the gem is now named eventfulapi. Support for the
55
108
  # evdbapi gem is being discontinued; please use the eventfulapi gem from now on.
56
- # - Much better at throwing an error when a network or server problem happens,
109
+ # - Much better at throwing an error when a network or server problem happens,
57
110
  # rather than failing silently and mysteriously
58
111
  # - Documentation improvements
59
112
  #
@@ -63,7 +116,7 @@
63
116
  #
64
117
  # - Fixed a minor documentation error
65
118
  #
66
- # ==== Version 2.0
119
+ # ==== Version 2.0
67
120
  #
68
121
  # Version 2.0 of this library includes some significant changes which may not
69
122
  # be backwards compatible. Specifically:
@@ -78,9 +131,9 @@
78
131
  # == Information
79
132
  #
80
133
  # Status:: Stable
81
- # Version:: 2.1.1
134
+ # Version:: 2.2.0
82
135
  # Date:: 2007-03-24
83
- # Current Author:: Paul Knight (mailto:pknight@eventful.com)
136
+ # Current Author:: Paul Knight (mailto:paul@eventful.com)
84
137
  # Previous Authors:: Joe Auricchio
85
138
  # Copyright:: Copyright (C) 2005-2007 Eventful Inc.
86
139
  # License:: This code is distributed under the same terms as Ruby itself (see http://www.ruby-lang.org/en/LICENSE.txt)
@@ -104,8 +157,7 @@ require 'cgi'
104
157
  require 'net/http'
105
158
  require 'base64'
106
159
  require 'digest/md5'
107
- require 'open-uri'
108
- require 'rexml/document'
160
+
109
161
 
110
162
 
111
163
 
@@ -113,97 +165,140 @@ require 'rexml/document'
113
165
  module Eventful
114
166
 
115
167
 
116
-
168
+
117
169
  # Version descriptor of this library
118
- VERSION = '2.1'
119
-
170
+ VERSION = '2.2.0'
171
+
120
172
  # Default API server to connect to
121
- DEFAULT_API_SERVER = 'api.eventful.com' #:nodoc:
173
+ DEFAULT_SERVER = 'api.eventful.com' #:nodoc:
122
174
  # Default server port
123
- DEFAULT_API_PORT = 80 #:nodoc:
175
+ DEFAULT_PORT = 80 #:nodoc:
124
176
  # Default server path
125
- DEFAULT_API_ROOT = '/yaml/' #:nodoc:
126
-
177
+ DEFAULT_ROOT = '/yaml/' #:nodoc:
178
+
127
179
  # Our POST data boundary
128
180
  BOUNDARY = '1E666D29B5E749F6A145BE8A576049E6' #:nodoc:
129
181
  BOUNDARY_MARKER = "--#{BOUNDARY}" #:nodoc:
130
182
  BOUNDARY_END_MARKER = "--#{BOUNDARY}--" #:nodoc:
131
-
132
-
133
-
183
+
184
+
185
+
134
186
  # Parent Error used for all Eventful exceptions
135
187
  class Error < StandardError ; end
136
-
188
+
137
189
  # An error that may also include the YAML response from the server
138
190
  class APIError < Error
139
191
  attr_reader :response
140
-
192
+
141
193
  # Creates a new exception.
142
194
  def initialize(response)
143
195
  super
144
196
  @response = response
145
197
  end
146
-
198
+
147
199
  # The error string returned by the API call.
148
200
  def to_s
149
201
  "#{@response['string']}: #{@response['description']}"
150
202
  end
151
203
  end
152
-
153
-
154
-
204
+
205
+
206
+
155
207
  # A class for working with the Eventful API.
156
208
  class API
157
-
158
-
159
-
209
+
210
+
211
+
160
212
  # Create an object for working with the Eventful API. Working with the API
161
213
  # requires an application key, which can be obtained at http://api.eventful.com/keys/
162
214
  #
163
215
  # Options may be:
164
216
  #
165
- # <tt>'user'</tt>:: Authenticate as this user, required for some API methods. A password must also be specified.
166
- # <tt>'password'</tt>:: Password for user authentication.
217
+ # <tt>:user</tt>:: Authenticate as this user, required for some API methods. A password must also be specified.
218
+ # <tt>:password</tt>:: Password for user authentication.
219
+ #
220
+ # If both <tt>user</tt> and <tt>password</tt> are specified, then digest
221
+ # authenticatino will be used. Otherise, basic authentication will be used.
222
+ # Please note that basic authentication sends passwords in the clear.
223
+ # For more information, please see http://api.eventful.com/docs/auth
224
+ #
225
+ # ==== Testing Against Another Server
226
+ #
227
+ # For testing, you may use the following options for specifying a
228
+ # different API server:
229
+ #
230
+ # <tt>:server</tt>:: Hostname of the API server, default <tt>api.eventful.com</tt>
231
+ # <tt>:root</tt>:: Path to the root of all method calls, default <tt>/yaml/</tt>
232
+ # <tt>:port</tt>:: Server port, default <tt>80</tt>
233
+ #
234
+ # If the server is behind HTTP authentication, you can use:
235
+ #
236
+ # <tt>:http_user</tt>:: Username for HTTP authentication
237
+ # <tt>:http_password</tt>:: Password for HTTP authenciation
238
+ #
239
+ # Please note that none of these five options are needed for using the Eventful API.
240
+ #
241
+ # ==== Example
167
242
  #
168
- # Example:
169
- #
170
243
  # eventful = Eventful::API.new 'app_key',
171
- # 'user' => 'username',
172
- # 'password' => 'password'
244
+ # :user => 'username',
245
+ # :password => 'password'
173
246
  #
174
247
  def initialize(app_key, options = {})
175
- @api_server = options['api_server'] || DEFAULT_API_SERVER
176
- @api_root = options['api_root'] || DEFAULT_API_ROOT
177
- @api_port = options['api_port'] || DEFAULT_API_PORT
178
-
179
- @auth_user = options['auth_user']
180
- @auth_password = options['auth_password']
181
-
182
- @authentication = nil
183
-
248
+ # Grab our arguments
249
+
250
+ @server = find_option [:server, :api_server], options, DEFAULT_SERVER
251
+ @root = find_option [:root, :api_root], options, DEFAULT_ROOT
252
+ @port = find_option [:port, :api_port], options, DEFAULT_PORT
253
+
254
+ @http_user = find_option [:http_user, :auth_user], options
255
+ @http_password = find_option [:http_password, :auth_password], options
256
+
257
+ user = find_option [:user], options
258
+ password = find_option [:password], options
259
+
184
260
  # User authentication
185
- if (options['user'] && options['password'])
186
- nonce = get_nonce app_key
187
-
261
+ if user and password
262
+ # Get a nonce; we expect an error response here, so rescue the exception and continue
263
+ begin
264
+ response = call 'users/login',
265
+ :app_key => app_key
266
+ rescue APIError => error
267
+ raise unless error.response['nonce']
268
+ nonce = error.response['nonce']
269
+ end
270
+
188
271
  # Login with a hash of the nonce and our password
189
- login_hash = Digest::MD5.hexdigest("#{nonce}:#{Digest::MD5.hexdigest(options['password'])}")
190
- response = call 'users/login',
191
- 'app_key' => app_key,
192
- 'user' => options['user'],
193
- 'nonce' => nonce,
194
- 'response' => login_hash
195
-
272
+ login_hash = Digest::MD5.hexdigest "#{nonce}:#{Digest::MD5.hexdigest(password)}"
273
+ response = call 'users/login',
274
+ :app_key => app_key,
275
+ :user => user,
276
+ :nonce => nonce,
277
+ :response => login_hash
278
+
196
279
  # Store authentication information and use it for all future calls
197
- @authentication = { 'app_key' => app_key,
198
- 'user' => options['user'],
199
- 'user_key' => response['user_key'] }
280
+ @authentication = { :app_key => app_key,
281
+ :user => user,
282
+ :user_key => response['user_key'] }
200
283
  else
201
- @authentication = { 'app_key' => app_key }
284
+ @authentication = { :app_key => app_key }
285
+ end
286
+ end
287
+
288
+
289
+
290
+ # Search through a method argument Hash for specified named parameters
291
+ def find_option(names, arguments, default = nil) #:nodoc:
292
+ result = default
293
+ names.each do |name|
294
+ result = arguments[name] || arguments[name.to_s] || result
202
295
  end
296
+ return result
203
297
  end
204
298
 
205
299
 
206
-
300
+
301
+
207
302
  # Prepares the body of the POST request
208
303
  def prepare_post(params) #:nodoc:
209
304
  content = ""
@@ -215,7 +310,7 @@ module Eventful
215
310
  content += "Content-Transfer-Encoding: binary\r\n\r\n"
216
311
  content += open(value) { |f| f.read } + "\r\n"
217
312
  else
218
- content += "Content-Disposition: form-data; name=\"#{CGI::escape(key.to_s)}\";\r\n\r\n#{value}\r\n"
313
+ content += "Content-Disposition: form-data; name=\"#{CGI::escape(key.to_s)}\";\r\n\r\n#{value}\r\n"
219
314
  end
220
315
  end
221
316
  content += BOUNDARY_END_MARKER
@@ -228,50 +323,42 @@ module Eventful
228
323
  # a hash. Please see the Eventful API documentation (http://api.eventful.com/docs)
229
324
  # for information about methods and their parameters.
230
325
  #
231
- # Example:
326
+ # ==== Example
232
327
  #
233
328
  # event = eventful.call 'events/get',
234
- # 'id' => 'E0-001-001042544-7'
329
+ # :id => 'E0-001-001042544-7'
235
330
  #
236
331
  def call(method, params = {})
237
332
  # Use available auth tokens
238
333
  params.merge! @authentication if @authentication
239
334
 
240
- response = Net::HTTP.start(@api_server, @api_port) do |connection|
241
- if @auth_user && @auth_password then
335
+ response = Net::HTTP.start(@server, @port) do |connection|
336
+ if @http_user and @http_password then
242
337
  connection.post(
243
- "#{@api_root}#{method}",
244
- prepare_post(params),
245
- "Content-type" => "multipart/form-data; boundary=#{BOUNDARY} ",
246
- "Authorization" => Base64.encode64("#{@auth_user}:#{@auth_password}"))
338
+ "#{@root}#{method}",
339
+ prepare_post(params),
340
+ "Content-type" => "multipart/form-data; boundary=#{BOUNDARY} ",
341
+ "Authorization" => Base64.encode64("#{@http_user}:#{@http_password}"))
247
342
  else
248
343
  connection.post(
249
- "#{@api_root}#{method}",
250
- prepare_post(params),
344
+ "#{@root}#{method}",
345
+ prepare_post(params),
251
346
  "Content-type" => "multipart/form-data; boundary=#{BOUNDARY} ")
252
347
  end
253
348
  end
254
-
349
+
255
350
  # Raise an exception if we didn't get a 2xx response code
256
351
  response.value
257
-
352
+
258
353
  yaml = YAML::load response.body
259
-
354
+
260
355
  # Raise an error if we got an API error
261
356
  raise APIError.new(yaml['error']) if yaml['error']
262
357
 
263
358
  return yaml
264
359
  end
265
-
266
- # Only intended for the first users/login authentication call
267
- def get_nonce(app_key) # :nodoc:
268
- open "http://#{@api_server}/rest/users/login?app_key=#{CGI::escape app_key}" do |f|
269
- (REXML::Document.new f.read).elements["error/nonce"].text
270
- end
271
- end
272
-
273
-
274
-
360
+
361
+
362
+
275
363
  end # class API
276
364
  end # module Eventful
277
-
metadata CHANGED
@@ -3,13 +3,13 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: eventfulapi
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.1.1
7
- date: 2007-04-24 00:00:00 -07:00
6
+ version: 2.2.0
7
+ date: 2007-05-14 00:00:00 -07:00
8
8
  summary: Interface to the Eventful API. http://eventful.com
9
9
  require_paths:
10
10
  - lib
11
- email: pknight@eventful.com
12
- homepage: http://api.evdb.com
11
+ email: paul@eventful.com
12
+ homepage: http://api.eventful.com
13
13
  rubyforge_project:
14
14
  description:
15
15
  autorequire: eventful/api