ordrin 0.1.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.
- data/bin/ordrindemo.rb +323 -0
- data/lib/ordrin/data.rb +148 -0
- data/lib/ordrin/errors.rb +147 -0
- data/lib/ordrin/normalize.rb +186 -0
- data/lib/ordrin/order.rb +79 -0
- data/lib/ordrin/ordrinapi.rb +66 -0
- data/lib/ordrin/restaurant.rb +56 -0
- data/lib/ordrin/user.rb +142 -0
- data/lib/ordrin.rb +58 -0
- metadata +72 -0
data/bin/ordrindemo.rb
ADDED
@@ -0,0 +1,323 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'date'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'ordrin'
|
8
|
+
rescue LoadError
|
9
|
+
require 'rubygems'
|
10
|
+
begin
|
11
|
+
require 'ordrin'
|
12
|
+
rescue LoadError
|
13
|
+
require_relative '../lib/ordrin'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module OrdrinDemo
|
18
|
+
#
|
19
|
+
# Global Variables
|
20
|
+
#
|
21
|
+
print "Please input your API key: "
|
22
|
+
STDOUT.flush
|
23
|
+
api_key = gets.chomp
|
24
|
+
|
25
|
+
@@api = Ordrin::APIs.new(api_key, :test)
|
26
|
+
|
27
|
+
# Create an Address object
|
28
|
+
@@address = Ordrin::Data::Address.new('1 Main Street', 'College Station', 'TX', '77840', '(555) 555-5555')
|
29
|
+
@@address_nick = 'addr1'
|
30
|
+
|
31
|
+
# Create a CreditCard object
|
32
|
+
@@first_name = 'Test'
|
33
|
+
@@last_name = 'User'
|
34
|
+
@@credit_card = Ordrin::Data::CreditCard.new("#{@@first_name} #{@@last_name}", '01', (Date.today.year+2).to_s, @@address, '4111111111111111', '123')
|
35
|
+
@@credit_card_nick = 'cc1'
|
36
|
+
|
37
|
+
unique_id = SecureRandom.uuid.to_s.gsub(/-/, '')
|
38
|
+
@@email = "demo+#{unique_id}ruby@ordr.in"
|
39
|
+
@@password = 'password'
|
40
|
+
@@login = Ordrin::Data::UserLogin.new(@@email, @@password)
|
41
|
+
@@alt_first_name = 'Example'
|
42
|
+
@@alt_email = "demo+#{unique_id}rubyalt@ordr.in"
|
43
|
+
@@alt_login = Ordrin::Data::UserLogin.new(@@alt_email, @@password)
|
44
|
+
@@new_password = 'password1'
|
45
|
+
|
46
|
+
#
|
47
|
+
# Restaurant demo functions
|
48
|
+
#
|
49
|
+
|
50
|
+
def OrdrinDemo.delivery_list_immediate_demo()
|
51
|
+
puts "Get a list of restaurants that will deliver if you order now"
|
52
|
+
print "Press enter to execute and see the response"
|
53
|
+
gets
|
54
|
+
delivery_list_immediate = @@api.restaurant.get_delivery_list('ASAP', @@address)
|
55
|
+
PP.pp(delivery_list_immediate)
|
56
|
+
return delivery_list_immediate
|
57
|
+
end
|
58
|
+
|
59
|
+
def OrdrinDemo.delivery_list_future_demo()
|
60
|
+
puts "Get a list of restaurants that will deliver if you order for 12 hours from now"
|
61
|
+
print "Press enter to execute and see the response"
|
62
|
+
gets
|
63
|
+
future_datetime = DateTime.now + 0.5 #A timestamp twelve hours in the future
|
64
|
+
delivery_list_later = @@api.restaurant.get_delivery_list(future_datetime, @@address)
|
65
|
+
PP.pp(delivery_list_later)
|
66
|
+
end
|
67
|
+
|
68
|
+
def OrdrinDemo.delivery_check_demo(restaurant_id)
|
69
|
+
puts "Get whether a particular restaurant will deliver if you order now"
|
70
|
+
print "Press enter to execute and see the response"
|
71
|
+
gets
|
72
|
+
delivery_check = @@api.restaurant.get_delivery_check(restaurant_id, 'ASAP', @@address)
|
73
|
+
PP.pp(delivery_check)
|
74
|
+
end
|
75
|
+
|
76
|
+
def OrdrinDemo.fee_demo(restaurant_id)
|
77
|
+
puts "Get fee and other info for ordering a given amount with a given tip"
|
78
|
+
print "Press enter to execute and see the response"
|
79
|
+
gets
|
80
|
+
subtotal = "$30.00"
|
81
|
+
tip = "$5.00"
|
82
|
+
fee_info = @@api.restaurant.get_fee(restaurant_id, subtotal, tip, 'ASAP', @@address)
|
83
|
+
PP.pp(fee_info)
|
84
|
+
end
|
85
|
+
|
86
|
+
def OrdrinDemo.detail_demo(restaurant_id)
|
87
|
+
puts "Get detailed information about a single restaurant"
|
88
|
+
print "Press enter to execute and see the response"
|
89
|
+
gets
|
90
|
+
restaurant_detail = @@api.restaurant.get_details(restaurant_id)
|
91
|
+
PP.pp(restaurant_detail)
|
92
|
+
return restaurant_detail
|
93
|
+
end
|
94
|
+
|
95
|
+
def OrdrinDemo.find_deliverable_time(restaurant_id)
|
96
|
+
puts "Find a time when this restaurant will deliver"
|
97
|
+
print "Press enter to execute and see the response"
|
98
|
+
gets
|
99
|
+
delivery_check = @@api.restaurant.get_delivery_check(restaurant_id, 'ASAP', @@address)
|
100
|
+
delivery = delivery_check['delivery']
|
101
|
+
if delivery
|
102
|
+
return 'ASAP'
|
103
|
+
end
|
104
|
+
dt = DateTime.now + 1/24.0
|
105
|
+
while not delivery
|
106
|
+
delivery_check = @@api.restaurant.get_delivery_check(restaurant_id, dt, @@address)
|
107
|
+
delivery = delivery_check['delivery']
|
108
|
+
dt += 1/24.0
|
109
|
+
end
|
110
|
+
return dt
|
111
|
+
end
|
112
|
+
#
|
113
|
+
# User demo functions
|
114
|
+
#
|
115
|
+
|
116
|
+
def OrdrinDemo.get_user_demo()
|
117
|
+
puts "Get information about a user"
|
118
|
+
print "Press enter to execute and see the response"
|
119
|
+
gets
|
120
|
+
user_info = @@api.user.get(@@login)
|
121
|
+
PP.pp(user_info)
|
122
|
+
end
|
123
|
+
|
124
|
+
def OrdrinDemo.create_user_demo()
|
125
|
+
puts "Create a user"
|
126
|
+
print "Press enter to execute and see the response"
|
127
|
+
gets
|
128
|
+
response = @@api.user.create(@@login, @@first_name, @@last_name)
|
129
|
+
PP.pp(response)
|
130
|
+
end
|
131
|
+
|
132
|
+
def OrdrinDemo.update_user_demo()
|
133
|
+
puts "Update a user"
|
134
|
+
print "Press enter to execute and see the response"
|
135
|
+
gets
|
136
|
+
response = @@api.user.update(@@login, @@alt_first_name, @@last_name)
|
137
|
+
PP.pp(response)
|
138
|
+
end
|
139
|
+
|
140
|
+
def OrdrinDemo.get_all_addresses_demo()
|
141
|
+
puts "Get a list of all saved addresses"
|
142
|
+
print "Press enter to execute and see the response"
|
143
|
+
gets
|
144
|
+
address_list = @@api.user.get_all_addresses(@@login)
|
145
|
+
PP.pp(address_list)
|
146
|
+
end
|
147
|
+
|
148
|
+
def OrdrinDemo.get_address_demo()
|
149
|
+
puts "Get an address by nickname"
|
150
|
+
print "Press enter to execute and see the response"
|
151
|
+
gets
|
152
|
+
addr = @@api.user.get_address(@@login, @@address_nick)
|
153
|
+
PP.pp(addr)
|
154
|
+
end
|
155
|
+
|
156
|
+
def OrdrinDemo.set_address_demo()
|
157
|
+
puts "Save an address with a nickname"
|
158
|
+
response = @@api.user.set_address(@@login, @@address_nick, @@address)
|
159
|
+
PP.pp(response)
|
160
|
+
end
|
161
|
+
|
162
|
+
def OrdrinDemo.remove_address_demo()
|
163
|
+
puts "Remove a saved address by nickname"
|
164
|
+
print "Press enter to execute and see the response"
|
165
|
+
gets
|
166
|
+
response = @@api.user.remove_address(@@login, @@address_nick)
|
167
|
+
PP.pp(response)
|
168
|
+
end
|
169
|
+
|
170
|
+
def OrdrinDemo.get_all_credit_cards_demo()
|
171
|
+
puts "Get a list of all saved credit cards"
|
172
|
+
credit_card_list = @@api.user.get_all_credit_cards(@@login)
|
173
|
+
PP.pp(credit_card_list)
|
174
|
+
end
|
175
|
+
|
176
|
+
def OrdrinDemo.get_credit_card_demo()
|
177
|
+
puts "Get a saved credit card by nickname"
|
178
|
+
print "Press enter to execute and see the response"
|
179
|
+
gets
|
180
|
+
credit_card = @@api.user.get_credit_card(@@login, @@credit_card_nick)
|
181
|
+
PP.pp(credit_card)
|
182
|
+
end
|
183
|
+
|
184
|
+
def OrdrinDemo.set_credit_card_demo()
|
185
|
+
puts "Save a credit card with a nickname"
|
186
|
+
print "Press enter to execute and see the response"
|
187
|
+
gets
|
188
|
+
response = @@api.user.set_credit_card(@@login, @@credit_card_nick, @@credit_card)
|
189
|
+
PP.pp(response)
|
190
|
+
end
|
191
|
+
|
192
|
+
def OrdrinDemo.remove_credit_card_demo()
|
193
|
+
puts "Remove a saved credit card by nickname"
|
194
|
+
print "Press enter to execute and see the response"
|
195
|
+
gets
|
196
|
+
response = @@api.user.remove_credit_card(@@login, @@credit_card_nick)
|
197
|
+
PP.pp(response)
|
198
|
+
end
|
199
|
+
|
200
|
+
def OrdrinDemo.get_order_history_demo(login)
|
201
|
+
puts "Get a list of all orders made by this user"
|
202
|
+
print "Press enter to execute and see the response"
|
203
|
+
gets
|
204
|
+
order_list = @@api.user.get_order_history(@@login)
|
205
|
+
PP.pp(order_list)
|
206
|
+
end
|
207
|
+
|
208
|
+
def OrdrinDemo.get_order_detail_demo(oid)
|
209
|
+
puts "Get the details of a particular order made by this user"
|
210
|
+
print "Press enter to execute and see the response"
|
211
|
+
gets
|
212
|
+
order_detail = @@api.user.get_order_detail(@@login, oid)
|
213
|
+
PP.pp(order_detail)
|
214
|
+
end
|
215
|
+
|
216
|
+
def OrdrinDemo.set_password_demo()
|
217
|
+
puts "Set a new password for a user"
|
218
|
+
print "Press enter to execute and see the response"
|
219
|
+
gets
|
220
|
+
response = @@api.user.set_password(@@login, @@new_password)
|
221
|
+
PP.pp(response)
|
222
|
+
end
|
223
|
+
|
224
|
+
#
|
225
|
+
# Order demo functions
|
226
|
+
#
|
227
|
+
|
228
|
+
def OrdrinDemo.anonymous_order_demo(restaurant_id, tray, date_time)
|
229
|
+
puts "Order food as someone without a user account"
|
230
|
+
print "Press enter to execute and see the response"
|
231
|
+
gets
|
232
|
+
tip = Random.rand(500)/100.0
|
233
|
+
response = @@api.order.order(restaurant_id, tray, tip, date_time, @@first_name, @@last_name, @@address, @@credit_card, @@email)
|
234
|
+
PP.pp(response)
|
235
|
+
end
|
236
|
+
|
237
|
+
def OrdrinDemo.create_user_and_order_demo(restaurant_id, tray, date_time)
|
238
|
+
puts "Order food and create an account"
|
239
|
+
print "Press enter to execute and see the response"
|
240
|
+
gets
|
241
|
+
tip = Random.rand(500)/100.0
|
242
|
+
response = @@api.order.order_create_user(restaurant_id, tray, tip, date_time, @@first_name, @@last_name, @@address, @@credit_card, @@alt_email, @@password)
|
243
|
+
PP.pp(response)
|
244
|
+
end
|
245
|
+
|
246
|
+
def OrdrinDemo.order_with_nicks_demo(restaurant_id, tray, date_time)
|
247
|
+
puts "Order food as a logged in user using previously stored address and credit card"
|
248
|
+
print "Press enter to execute and see the response"
|
249
|
+
gets
|
250
|
+
tip = Random.rand(500)/100.0
|
251
|
+
response = @@api.order.order(restaurant_id, tray, tip, date_time, @@first_name, @@last_name, @@address_nick, @@credit_card_nick, nil, @@login)
|
252
|
+
PP.pp(response)
|
253
|
+
return response
|
254
|
+
end
|
255
|
+
|
256
|
+
def OrdrinDemo.find_item_to_order(item_list)
|
257
|
+
for item in item_list
|
258
|
+
if item['is_orderable']=='1'
|
259
|
+
if item['price'].to_f>=5.00
|
260
|
+
return item['id']
|
261
|
+
end
|
262
|
+
else
|
263
|
+
if item.has_key?('children')
|
264
|
+
item_id = find_item_to_order(item['children'])
|
265
|
+
unless item_id.nil?
|
266
|
+
return item_id
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
nil
|
272
|
+
end
|
273
|
+
|
274
|
+
|
275
|
+
#
|
276
|
+
# Main
|
277
|
+
#
|
278
|
+
def OrdrinDemo.run_demo()
|
279
|
+
puts "Run through the entire demo sequence"
|
280
|
+
# Restaurant functions
|
281
|
+
delivery_list = delivery_list_immediate_demo()
|
282
|
+
delivery_list_future_demo()
|
283
|
+
restaurant_id = delivery_list[0]['id']
|
284
|
+
delivery_check_demo(restaurant_id)
|
285
|
+
fee_demo(restaurant_id)
|
286
|
+
detail = detail_demo(restaurant_id)
|
287
|
+
|
288
|
+
# User functions
|
289
|
+
create_user_demo()
|
290
|
+
get_user_demo()
|
291
|
+
update_user_demo()
|
292
|
+
get_user_demo()
|
293
|
+
set_address_demo()
|
294
|
+
get_address_demo()
|
295
|
+
set_credit_card_demo()
|
296
|
+
get_credit_card_demo()
|
297
|
+
|
298
|
+
# Order functions
|
299
|
+
order_date_time = find_deliverable_time(restaurant_id)
|
300
|
+
puts "Ordering food at #{order_date_time}"
|
301
|
+
item_id = find_item_to_order(detail['menu'])
|
302
|
+
item = Ordrin::Data::TrayItem.new(item_id, 10)
|
303
|
+
tray = Ordrin::Data::Tray.new(item)
|
304
|
+
anonymous_order_demo(restaurant_id, tray, order_date_time)
|
305
|
+
order = order_with_nicks_demo(restaurant_id, tray, order_date_time)
|
306
|
+
unless order.nil?
|
307
|
+
get_order_detail_demo(order['refnum'])
|
308
|
+
end
|
309
|
+
|
310
|
+
create_user_and_order_demo(restaurant_id, tray, order_date_time)
|
311
|
+
get_order_history_demo(@@alt_login)
|
312
|
+
|
313
|
+
# Clean up/removing stuff
|
314
|
+
remove_address_demo()
|
315
|
+
get_all_addresses_demo()
|
316
|
+
remove_credit_card_demo()
|
317
|
+
get_all_credit_cards_demo()
|
318
|
+
set_password_demo()
|
319
|
+
#After changing the password I must change the login object to continue to access user info
|
320
|
+
end
|
321
|
+
|
322
|
+
run_demo()
|
323
|
+
end
|
data/lib/ordrin/data.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require_relative 'normalize'
|
3
|
+
module Ordrin
|
4
|
+
module Data
|
5
|
+
# Base class for objects that can save any data with the constructor and then
|
6
|
+
# extract it as a dictionary
|
7
|
+
class OrdrinData
|
8
|
+
# Return a dictionary of particular fields to values, determined per subclass
|
9
|
+
def make_dict
|
10
|
+
dict = {}
|
11
|
+
fields.map {|f| dict[f.to_s]=self.send(f) unless self.send(f).nil?}
|
12
|
+
return dict
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Represents a street address
|
17
|
+
class Address < OrdrinData
|
18
|
+
|
19
|
+
attr_reader :addr, :city, :state, :zip, :phone, :addr2, :fields
|
20
|
+
|
21
|
+
# Store the parts of the address as fields in this object.
|
22
|
+
# Arguments:
|
23
|
+
# addr -- Street address
|
24
|
+
# city -- City
|
25
|
+
# state -- State
|
26
|
+
# zip -- Zip code
|
27
|
+
# phone -- Phone number
|
28
|
+
# addr2 -- Optional second street address line
|
29
|
+
def initialize(addr, city, state, zip, phone, addr2='')
|
30
|
+
@fields = [:addr, :city, :state, :zip, :phone, :addr2]
|
31
|
+
@addr = addr
|
32
|
+
@city = city
|
33
|
+
@state = Normalize.normalize(state, :state)
|
34
|
+
@zip = Normalize.normalize(zip, :zip)
|
35
|
+
@phone = Normalize.normalize(phone, :phone)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Represents information about a credit card
|
40
|
+
class CreditCard < OrdrinData
|
41
|
+
|
42
|
+
attr_reader :expiry_month, :expiry_year, :number, :cvc, :type, :name, :bill_address, :fields
|
43
|
+
|
44
|
+
# Store the credit card info as fields in this object.
|
45
|
+
# Arguments:
|
46
|
+
# name -- The name (first and last) on the credit card
|
47
|
+
# expiry_month -- The month that the card expires (two digits)
|
48
|
+
# expiry_year -- The year that the card expires (four digits)
|
49
|
+
# bill_address -- The billing address. Should be an Ordrin::Data::Address object
|
50
|
+
# number -- The credit card number
|
51
|
+
# cvc -- The card verification number
|
52
|
+
def initialize(name, expiry_month, expiry_year, bill_address, number, cvc)
|
53
|
+
@fields = [:number, :cvc, :expiry_month, :expiry_year, :expiry,
|
54
|
+
:bill_addr, :bill_addr2, :bill_city, :bill_state, :bill_zip,
|
55
|
+
:phone, :name]
|
56
|
+
@expiry_month = Normalize.normalize(expiry_month, :month)
|
57
|
+
@expiry_year = Normalize.normalize(expiry_year, :year)
|
58
|
+
@number, @cvc, @type = Normalize.normalize([number, cvc], :credit_card)
|
59
|
+
@name = name
|
60
|
+
@bill_address = bill_address
|
61
|
+
end
|
62
|
+
|
63
|
+
def bill_addr
|
64
|
+
@bill_address.addr
|
65
|
+
end
|
66
|
+
|
67
|
+
def bill_addr2
|
68
|
+
@bill_address.addr2
|
69
|
+
end
|
70
|
+
|
71
|
+
def bill_city
|
72
|
+
@bill_address.city
|
73
|
+
end
|
74
|
+
|
75
|
+
def bill_state
|
76
|
+
@bill_address.state
|
77
|
+
end
|
78
|
+
|
79
|
+
def bill_zip
|
80
|
+
@bill_address.zip
|
81
|
+
end
|
82
|
+
|
83
|
+
def phone
|
84
|
+
@bill_address.phone
|
85
|
+
end
|
86
|
+
|
87
|
+
# A combination of the expiry_month and expiry_date
|
88
|
+
def expiry
|
89
|
+
"#{expiry_month}/#{expiry_year}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#Represents a user's login information
|
94
|
+
class UserLogin < OrdrinData
|
95
|
+
|
96
|
+
attr_reader :email, :password, :fields
|
97
|
+
|
98
|
+
# Store the email and password in this object. Saves only the hash of the
|
99
|
+
# password, not the password itself
|
100
|
+
# Arguments:
|
101
|
+
# email -- The user's email address
|
102
|
+
# password -- The user's password (in plain text)
|
103
|
+
def initialize(email, password)
|
104
|
+
@fields = [:email, :password]
|
105
|
+
@email = email
|
106
|
+
@password = UserLogin.hash_password(password)
|
107
|
+
end
|
108
|
+
|
109
|
+
def UserLogin.hash_password(password)
|
110
|
+
return Digest::SHA256.new.hexdigest(password)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Represents a single item in an order
|
115
|
+
class TrayItem
|
116
|
+
|
117
|
+
# Store the descriptors of an order item in this object.
|
118
|
+
# Arguments:
|
119
|
+
# item_id -- the restaurants's numerial ID for the item
|
120
|
+
# quantity -- the quantity
|
121
|
+
# options -- any number of options to apply to the item
|
122
|
+
def initialize(item_id, quantity, *options)
|
123
|
+
@item_id = Normalize.normalize(item_id, :number)
|
124
|
+
@quantity = Normalize.normalize(quantity, :number)
|
125
|
+
@options = options.map {|opt| Normalize.normalize(opt, :number)}
|
126
|
+
end
|
127
|
+
|
128
|
+
def to_s
|
129
|
+
"#{@item_id}/#{@quantity},#{@options*','}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Represents a list of items in an order
|
134
|
+
class Tray
|
135
|
+
|
136
|
+
# Store the list of items in this object. Each argument should be of type Item
|
137
|
+
# Arguments:
|
138
|
+
# items -- A list of items to be ordered in this tray
|
139
|
+
def initialize(*items)
|
140
|
+
@items = items
|
141
|
+
end
|
142
|
+
|
143
|
+
def to_s
|
144
|
+
return @items*'+'
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Ordrin
|
2
|
+
module Errors
|
3
|
+
# This is the base class for errors specific to this ordrin package
|
4
|
+
class OrdrinError < Exception
|
5
|
+
attr_reader :msg
|
6
|
+
|
7
|
+
def initialize(msg=nil)
|
8
|
+
@msg = msg
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# This error encapsulates an API error returned by the server.
|
13
|
+
class ApiError < OrdrinError
|
14
|
+
attr_reader :text
|
15
|
+
def initialize(msg=nil, text=nil)
|
16
|
+
super(msg)
|
17
|
+
@text = text
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"ApiError(msg='#{msg}', text='#{text}')"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# This error indicates that the server returned a response that could not be
|
26
|
+
# parsed into JSON
|
27
|
+
class ApiInvalidResponseError < OrdrinError
|
28
|
+
def to_s
|
29
|
+
"ApiInvalidResponseError(msg='#{msg}')"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def Errors.state
|
34
|
+
lambda do |value|
|
35
|
+
ArgumentError.new("State must be a two letter postal code abbreviation: #{value}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def Errors.money
|
40
|
+
lambda do |value|
|
41
|
+
ArgumentError.new("Money must be dollars.cents: #{value}")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def Errors.zip
|
46
|
+
lambda do |value|
|
47
|
+
ArgumentError.new("Zip code must be exactly 5 digits: #{value}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def Errors.phone
|
52
|
+
lambda do |value|
|
53
|
+
ArgumentError.new("Phone numbers must have exactly 10 digits: #{value}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def Errors.number
|
58
|
+
lambda do |value|
|
59
|
+
ArgumentError.new("This value must be only digits: #{value}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def Errors.month
|
64
|
+
lambda do |value|
|
65
|
+
ArgumentError.new("Months must be two digits: #{value}")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def Errors.year
|
70
|
+
lambda do |value|
|
71
|
+
ArgumentError.new("Years must be four digits: #{value}")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def Errors.cvc
|
76
|
+
lambda do |value|
|
77
|
+
ArgumentError.new("Credit card CVC must be 3 or 4 digits, depending on the card type: #{value}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def Errors.credit_card
|
82
|
+
lambda do |value|
|
83
|
+
ArgumentError.new("Credit card number must be a valid AmEx, Discover, Mastercard, or Visa card number: #{value}")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def Errors.email
|
88
|
+
lambda do |value|
|
89
|
+
ArgumentError.new("Bad email format: #{value}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def Errors.normalizer
|
94
|
+
lambda do |value|
|
95
|
+
ArgumentError.new("Unknown validator name: #{value}")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def Errors.nick
|
100
|
+
lambda do |value|
|
101
|
+
ArgumentError.new("Nick names can only have letters, nubmers, dashes, and underscores: #{value}")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def Errors.date_time
|
106
|
+
lambda do |value|
|
107
|
+
ArgumentError.new("date_time must be a datetime.datetime object or the string 'ASAP': #{value}")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def Errors.date
|
112
|
+
lambda do |value|
|
113
|
+
ArgumentError.new("date must be a datetime.datetime or datetime.date object or the string 'ASAP': #{value}")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def Errors.time
|
118
|
+
lambda do |value|
|
119
|
+
ArgumentError.new("time must be a datetime.datetime or datetime.time object: #{value}")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def Errors.url
|
124
|
+
lambda do |value|
|
125
|
+
ArgumentError.new("url must be a proper url: #{value}")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def Errors.method
|
130
|
+
lambda do |value|
|
131
|
+
ArgumentError.new("method must be a word: #{value}")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def Errors.alphanum
|
136
|
+
lambda do |value|
|
137
|
+
ArgumentError.new("This value must be alphanumeric: #{value}")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def Errors.request_method
|
142
|
+
lambda do |value|
|
143
|
+
ApiError.new("Method not a valid HTTP request method: #{value}")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require_relative 'errors'
|
2
|
+
|
3
|
+
module Ordrin
|
4
|
+
module Normalize
|
5
|
+
class Normalizers
|
6
|
+
private
|
7
|
+
def regex(regex, error)
|
8
|
+
lambda do |value|
|
9
|
+
result = value.to_s[regex]
|
10
|
+
if result.nil?
|
11
|
+
raise error[value]
|
12
|
+
else
|
13
|
+
result
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
public
|
19
|
+
def phone(phone_number)
|
20
|
+
#strips out everything but digits from the phone number
|
21
|
+
phone = phone_number.to_s.gsub(/\D/, '')
|
22
|
+
if phone.length == 10
|
23
|
+
phone[/^(\d{3})(\d{3})(\d{4})$/]
|
24
|
+
"#{$1}-#{$2}-#{$3}"
|
25
|
+
else
|
26
|
+
raise Errors.phone[phone_number]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def money(money)
|
31
|
+
value = money.to_s.gsub(/,/, '')[/^\$?(\d+(\.\d+)?)$/, 1]
|
32
|
+
if value.nil?
|
33
|
+
raise Errors.money[money]
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def datetime(date_time)
|
40
|
+
if date_time.to_s.upcase == 'ASAP'
|
41
|
+
'ASAP'
|
42
|
+
else
|
43
|
+
begin
|
44
|
+
date_time.strftime('%m-%d+%H:%M')
|
45
|
+
rescue NoMethodError
|
46
|
+
raise Errors.date_time[date_time]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def date(date)
|
52
|
+
if date.to_s.upcase == 'ASAP'
|
53
|
+
'ASAP'
|
54
|
+
else
|
55
|
+
begin
|
56
|
+
date.strftime('%m-%d')
|
57
|
+
rescue NoMethodError
|
58
|
+
raise Errors.date[date_time]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def time(time)
|
64
|
+
if time.to_s.upcase == 'ASAP'
|
65
|
+
'ASAP'
|
66
|
+
else
|
67
|
+
begin
|
68
|
+
time.strftime('%m-%d+%H:%M')
|
69
|
+
rescue NoMethodError
|
70
|
+
raise Errors.time[date_time]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def url(url)
|
76
|
+
url.to_s[/^(https?:\/\/)[-\w.~]+(:\d+)?(\/[-\w.~]+)*/]
|
77
|
+
end
|
78
|
+
|
79
|
+
def state(state)
|
80
|
+
state = state.to_s[/^[A-Za-z]{2}$/]
|
81
|
+
if state.nil?
|
82
|
+
raise Errors.state[state]
|
83
|
+
else
|
84
|
+
state.upcase
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def cc_type(cc_number)
|
90
|
+
cc_map = {'American Express' => /^3[47]\d{13}$/,
|
91
|
+
'Visa' => /^4\d{12}(?:\d{3})?$/,
|
92
|
+
'Mastercard' => /^5[1-5]\d{14}$/,
|
93
|
+
'Discover' => /^6(?:011|5\d{2})\d{12}$/}
|
94
|
+
|
95
|
+
type = nil
|
96
|
+
cc_map.each {|key, value| type = key unless cc_number[value].nil?}
|
97
|
+
type
|
98
|
+
end
|
99
|
+
|
100
|
+
def luhn_checksum(card_number)
|
101
|
+
digits = card_number.to_s.scan(/./).map(&:to_i)
|
102
|
+
checksum = 0
|
103
|
+
digits.each_index do |index|
|
104
|
+
digit = digits[index]
|
105
|
+
if (digits.length-index)%2==1
|
106
|
+
checksum += digit
|
107
|
+
else
|
108
|
+
checksum += 2 * digit
|
109
|
+
end
|
110
|
+
end
|
111
|
+
checksum % 10
|
112
|
+
end
|
113
|
+
|
114
|
+
def luhn_valid?(card_number)
|
115
|
+
luhn_checksum(card_number) == 0
|
116
|
+
end
|
117
|
+
|
118
|
+
public
|
119
|
+
def credit_card(values)
|
120
|
+
number, cvc = values
|
121
|
+
num = number.to_s.gsub(/\D/, '')
|
122
|
+
unless luhn_valid?(num)
|
123
|
+
raise Errors.credit_card[number]
|
124
|
+
end
|
125
|
+
card_type = cc_type(num)
|
126
|
+
if card_type.nil?
|
127
|
+
raise Errors.credit_card[number]
|
128
|
+
else
|
129
|
+
if card_type=='American Express'
|
130
|
+
cvc_length = 4
|
131
|
+
else
|
132
|
+
cvc_length = 3
|
133
|
+
end
|
134
|
+
if cvc.length == cvc_length and !cvc.to_s[/^\d+$/].nil?
|
135
|
+
[num, cvc, card_type]
|
136
|
+
else
|
137
|
+
raise Errors.cvc[cvc]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def unchecked(value)
|
143
|
+
value.to_s
|
144
|
+
end
|
145
|
+
|
146
|
+
def name(value)
|
147
|
+
unchecked(value)
|
148
|
+
end
|
149
|
+
|
150
|
+
def zip(zip)
|
151
|
+
regex(/^\d{5}$/, Errors.zip)[zip]
|
152
|
+
end
|
153
|
+
|
154
|
+
def number(num)
|
155
|
+
regex(/^\d+/, Errors.number)[num]
|
156
|
+
end
|
157
|
+
|
158
|
+
def year(year)
|
159
|
+
regex(/^\d{4}$/, Errors.year)[year]
|
160
|
+
end
|
161
|
+
|
162
|
+
def month(mon)
|
163
|
+
regex(/^\d{2}$/, Errors.month)[mon]
|
164
|
+
end
|
165
|
+
|
166
|
+
def email(email)
|
167
|
+
regex(/^[^@\s]+@[^@\s]+\.[a-zA-Z]{2,3}/, Errors.email)[email]
|
168
|
+
end
|
169
|
+
|
170
|
+
def nick(nick)
|
171
|
+
regex(/^[-\w]+/, Errors.nick)[nick]
|
172
|
+
end
|
173
|
+
|
174
|
+
def alphanum(value)
|
175
|
+
regex(/^[a-zA-Z\d]+$/, Errors.alphanum)[value]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
@@normalizer = Normalizers.new
|
180
|
+
|
181
|
+
public
|
182
|
+
def Normalize.normalize(value, normalizer)
|
183
|
+
@@normalizer.send(normalizer, value)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
data/lib/ordrin/order.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative 'ordrinapi'
|
2
|
+
require_relative 'normalize'
|
3
|
+
require_relative 'data'
|
4
|
+
|
5
|
+
module Ordrin
|
6
|
+
# This class will be used to access the order API. All return values
|
7
|
+
# are documented at http://ordr.in/developers/order
|
8
|
+
class OrderApi < OrdrinApi
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
#Put all of the data that needs to be passed to the POST request normalized into a dict.
|
13
|
+
def build_dict(restaurant_id, tray, tip, delivery_date_time, first_name, last_name, address, credit_card, email, login=nil)
|
14
|
+
data = {'restaurant_id' => Normalize.normalize(restaurant_id, :number),
|
15
|
+
'tray' => tray.to_s,
|
16
|
+
'tip' => Normalize.normalize(tip, :money),
|
17
|
+
'delivery_date' => Normalize.normalize(delivery_date_time, :date)}
|
18
|
+
if data['delivery_date'] != 'ASAP'
|
19
|
+
data['delivery_time'] = Normalize.normalize(delivery_date_time, :time)
|
20
|
+
end
|
21
|
+
data['first_name'] = Normalize.normalize(first_name, :name)
|
22
|
+
data['last_name'] = Normalize.normalize(last_name, :name)
|
23
|
+
begin
|
24
|
+
data.merge!(address.make_dict)
|
25
|
+
rescue NoMethodError=>e
|
26
|
+
data['nick'] = Normalize.normalize(address, :nick)
|
27
|
+
end
|
28
|
+
if login.nil?
|
29
|
+
data['em'] = Normalize.normalize(email, :email)
|
30
|
+
end
|
31
|
+
begin
|
32
|
+
credit_card.make_dict.each_pair do |key, value|
|
33
|
+
data["card_#{key}"] = value
|
34
|
+
end
|
35
|
+
rescue NoMethodError=>e
|
36
|
+
data['card_nick'] = Normalize.normalize(credit_card, :nick)
|
37
|
+
end
|
38
|
+
data['type'] = 'res'
|
39
|
+
return data
|
40
|
+
end
|
41
|
+
|
42
|
+
public
|
43
|
+
# Place an order, either anonymously or as a logged in user. At least one
|
44
|
+
# of email and login must be passed. If both are passed, email will be ignored.
|
45
|
+
# Arguments:
|
46
|
+
# restaurant_id -- Ordr.in's restaurant identifier
|
47
|
+
# tray -- A tray of food to order. Should be an ordrin.data.Tray object
|
48
|
+
# tip -- The tip amount
|
49
|
+
# delivery_date_time -- Either 'ASAP' or a datetime object in the future
|
50
|
+
# first_name -- The orderer's first name
|
51
|
+
# last_name -- The orderer's last name
|
52
|
+
# address -- An address object (Ordrin::Data::Address) or the nickname of a saved address
|
53
|
+
# credit_card -- A credit card object (Ordrin::Data::CreditCard) or the nickname of a saved credit card
|
54
|
+
# email -- The email address of an anonymous user
|
55
|
+
# login -- The logged in user's login information. Should be an ordrin.data.UserLogin object
|
56
|
+
def order(restaurant_id, tray, tip, delivery_date_time, first_name, last_name, address, credit_card, email=nil, login=nil)
|
57
|
+
data = build_dict(restaurant_id, tray, tip, delivery_date_time, first_name, last_name, address, credit_card, email, login)
|
58
|
+
return call_api(:post, ['o', restaurant_id], login, data)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Place an order and create a user account
|
62
|
+
# Arguments:
|
63
|
+
# restaurant_id -- Ordr.in's restaurant identifier
|
64
|
+
# tray -- A tray of food to order. Should be an ordrin.data.Tray object
|
65
|
+
# tip -- The tip amount
|
66
|
+
# delivery_date_time -- Either 'ASAP' or a datetime object in the future
|
67
|
+
# first_name -- The orderer's first name
|
68
|
+
# last_name -- The orderer's last name
|
69
|
+
# address -- An address object (Ordrin::Data::Address) or the nickname of a saved address
|
70
|
+
# credit_card -- A credit card object (Ordrin::Data::CreditCard) or the nickname of a saved credit card
|
71
|
+
# email -- The email address of the user
|
72
|
+
# password -- The user's password (in plain text)
|
73
|
+
def order_create_user(restaurant_id, tray, tip, delivery_date_time, first_name, last_name, address, credit_card, email, password)
|
74
|
+
data = build_dict(restaurant_id, tray, tip, delivery_date_time, first_name, last_name, address, credit_card, email)
|
75
|
+
data['pw'] = Data::UserLogin.hash_password(password)
|
76
|
+
return call_api(:post, ['o', restaurant_id], nil, data)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require_relative 'normalize'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
require 'digest'
|
5
|
+
|
6
|
+
module Ordrin
|
7
|
+
# A base object for calling one part of the ordr.in API
|
8
|
+
class OrdrinApi
|
9
|
+
|
10
|
+
attr_reader :base_url
|
11
|
+
|
12
|
+
# Save the url and key parameters in the object
|
13
|
+
# Arguments:
|
14
|
+
# key -- The developer's API key
|
15
|
+
# base_url -- the url that all API call urls will expand from
|
16
|
+
def initialize(key, base_url)
|
17
|
+
@key = key
|
18
|
+
@base_url = Normalize.normalize(base_url, :url)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
# Calls the api at the saved url and returns the return value as Python data structures.
|
24
|
+
# Rethrows any api error as a Ruby exception
|
25
|
+
def call_api(method, arguments, login=nil, data=nil)
|
26
|
+
methods = {:get => Net::HTTP::Get,
|
27
|
+
:post => Net::HTTP::Post,
|
28
|
+
:put => Net::HTTP::Put,
|
29
|
+
:delete => Net::HTTP::Delete}
|
30
|
+
method = methods[method]
|
31
|
+
uri = ('/'+(arguments.collect {|a| URI.encode a.to_s})*'/')
|
32
|
+
full_url = URI.parse(base_url+uri)
|
33
|
+
req = method.new(full_url.request_uri)
|
34
|
+
unless data.nil?
|
35
|
+
req.body = URI.encode_www_form(data)
|
36
|
+
end
|
37
|
+
unless @key.empty?
|
38
|
+
req['X-NAAMA-CLIENT-AUTHENTICATION'] = "id=\"#{@key}\", version=\"1\""
|
39
|
+
end
|
40
|
+
unless login.nil?
|
41
|
+
hash_code = Digest::SHA256.new.hexdigest("#{login.password}#{login.email}#{uri}")
|
42
|
+
req['X-NAAMA-AUTHENTICATION'] = "username=\"#{login.email}\", response=\"#{hash_code}\", version=\"1\""
|
43
|
+
end
|
44
|
+
http = Net::HTTP.new(full_url.host, full_url.port)
|
45
|
+
if full_url.scheme == "https"
|
46
|
+
http.use_ssl = true
|
47
|
+
http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem")
|
48
|
+
end
|
49
|
+
res = http.start {|http| http.request(req)}
|
50
|
+
#error if not OK response
|
51
|
+
res.value
|
52
|
+
result = JSON.parse(res.body)
|
53
|
+
if result.is_a? Hash
|
54
|
+
if result.has_key?('_error') and result['_error']!=0
|
55
|
+
if result.has_key?('text')
|
56
|
+
raise Errors::ApiError.new(result['msg'], result['text'])
|
57
|
+
else
|
58
|
+
raise Errors::ApiError.new(result['msg'])
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
end
|
63
|
+
result
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative 'ordrinapi'
|
2
|
+
require_relative 'normalize'
|
3
|
+
|
4
|
+
module Ordrin
|
5
|
+
# This object's methods access the ordr.in restaurant API. All return values
|
6
|
+
# are documented at http://ordr.in/developers/restaurant
|
7
|
+
class RestaurantApi < OrdrinApi
|
8
|
+
# Get a list of dicts representing restaurants that will deliver to the
|
9
|
+
# given address at the given time.
|
10
|
+
# Arguments:
|
11
|
+
# date_time -- Either 'ASAP' or a datetime object in the future
|
12
|
+
# address -- the address to deliver to. Should be an Ordrin::Data::Address object
|
13
|
+
def get_delivery_list(date_time, address)
|
14
|
+
dt = Normalize.normalize(date_time, :datetime)
|
15
|
+
return call_api(:get, ['dl', dt, address.zip, address.city, address.addr])
|
16
|
+
end
|
17
|
+
|
18
|
+
# Get data about a given restaurant, including whether it will deliver to
|
19
|
+
# the specified address at the specified time
|
20
|
+
# Arguments:
|
21
|
+
# restaurant_id -- Ordr.in's restaurant identifier
|
22
|
+
# date_time -- Either 'ASAP' or a datetime object in the future
|
23
|
+
# address -- the address to deliver to. Should be an Ordrin::Data::Address object
|
24
|
+
def get_delivery_check(restaurant_id, date_time, address)
|
25
|
+
dt = Normalize.normalize(date_time, :datetime)
|
26
|
+
restauant_id = Normalize.normalize(restaurant_id, :number)
|
27
|
+
return call_api(:get, ['dc', restaurant_id, dt, address.zip, address.city, address.addr])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get data about a given restaurant, including whether it will deliver to
|
31
|
+
# the specified address at the specified time, and what the fee will be on an
|
32
|
+
# order with the given subtotal and tip
|
33
|
+
# Arguments:
|
34
|
+
# restaurant_id -- Ordr.in's restaurant identifier
|
35
|
+
# subtotal -- the subtotal of the order
|
36
|
+
# tip -- the tip on the order
|
37
|
+
# date_time -- Either 'ASAP' or a datetime object in the future
|
38
|
+
# address -- the address to deliver to. Should be an Ordrin::Data::Address object
|
39
|
+
def get_fee(restaurant_id, subtotal, tip, date_time, address)
|
40
|
+
dt = Normalize.normalize(date_time, :datetime)
|
41
|
+
restaurant_id = Normalize.normalize(restaurant_id, :number)
|
42
|
+
subtotal = Normalize.normalize(subtotal, :money)
|
43
|
+
tip = Normalize.normalize(tip, :money)
|
44
|
+
return call_api(:get, ['fee', restaurant_id, subtotal, tip, dt, address.zip, address.city, address.addr])
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get details of the given restaurant, including contact information and
|
48
|
+
# the menu
|
49
|
+
# Arguments:
|
50
|
+
# restaurant_id -- Ordr.in's restaurant identifier
|
51
|
+
def get_details(restaurant_id)
|
52
|
+
restaurant_id = Normalize.normalize(restaurant_id, :number)
|
53
|
+
return call_api(:get, ['rd', restaurant_id])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/ordrin/user.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require_relative 'ordrinapi'
|
2
|
+
require_relative 'normalize'
|
3
|
+
require_relative 'data'
|
4
|
+
|
5
|
+
module Ordrin
|
6
|
+
# This class will be used to access the user API. All return values
|
7
|
+
# are documented at http://ordr.in/developers/user
|
8
|
+
class UserApi < OrdrinApi
|
9
|
+
# Gets account information for the user associated with login
|
10
|
+
# Arguments:
|
11
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
12
|
+
def get(login)
|
13
|
+
return call_api(:get, ['u', login.email], login)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates account for the user associated with login. Throws a relevant exception
|
17
|
+
# on failure.
|
18
|
+
# Arguments:
|
19
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
20
|
+
# first_name -- the user's first name
|
21
|
+
# last_name -- the user's last name
|
22
|
+
def create(login, first_name, last_name)
|
23
|
+
data = {'email' => login.email,
|
24
|
+
'first_name' => Normalize.normalize(first_name, :name),
|
25
|
+
'last_name' => Normalize.normalize(last_name, :name),
|
26
|
+
'pw' => login.password}
|
27
|
+
return call_api(:post, ['u', login.email], nil, data)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Updates account for the user associated with login. Throws a relevant exception
|
31
|
+
# on failure.
|
32
|
+
# Arguments:
|
33
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
34
|
+
# first_name -- the user's first name
|
35
|
+
# last_name -- the user's last name
|
36
|
+
def update(login, first_name, last_name)
|
37
|
+
data = {'email' => login.email,
|
38
|
+
'first_name' => Normalize.normalize(first_name, :name),
|
39
|
+
'last_name' => Normalize.normalize(last_name, :name),
|
40
|
+
'pw' => login.password}
|
41
|
+
return call_api(:post, ['u', login.email], login, data)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get a list of all saved addresses for the user associated with login.
|
45
|
+
# Arguments:
|
46
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
47
|
+
def get_all_addresses(login)
|
48
|
+
return call_api(:get, ['u', login.email, 'addrs'], login)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get a saved address belonging to the logged in user by nickname.
|
52
|
+
# Arguments:
|
53
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
54
|
+
# addr_nick -- the nickname of the address to get
|
55
|
+
def get_address(login, addr_nick)
|
56
|
+
return call_api(:get, ['u', login.email, 'addrs', Normalize.normalize(addr_nick, :nick)], login)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Save an address by nickname for the logged in user
|
60
|
+
# Throws a relevant exception on failure
|
61
|
+
# Arguments:
|
62
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
63
|
+
# addr_nick -- the nickname of the address to save
|
64
|
+
# address -- the address to save. Should be an Ordrin::Data::Address object
|
65
|
+
def set_address(login, addr_nick, address)
|
66
|
+
return call_api(:put, ['u', login.email, 'addrs', Normalize.normalize(addr_nick, :nick)], login, address.make_dict)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Remove an address, saved by the logged in user, by nickname
|
70
|
+
# Throws a relevant exception on failure.
|
71
|
+
# Arguments:
|
72
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
73
|
+
# addr_nick -- the nickname of the address to remove
|
74
|
+
def remove_address(login, addr_nick)
|
75
|
+
return call_api(:delete, ['u', login.email, 'addrs', Normalize.normalize(addr_nick, :nick)], login)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get a list of all saved credit cards for the user associated with login.
|
79
|
+
# Arguments:
|
80
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
81
|
+
def get_all_credit_cards(login)
|
82
|
+
return call_api(:get, ['u', login.email, 'ccs'], login)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get a saved credit card belonging to the logged in user by nickname.
|
86
|
+
# Arguments:
|
87
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
88
|
+
# card_nick -- the nickname of the credit card to get
|
89
|
+
def get_credit_card(login, card_nick)
|
90
|
+
return call_api(:get, ['u', login.email, 'ccs', Normalize.normalize(card_nick, :nick)], login)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Save an credit card by nickname for the logged in user
|
94
|
+
# Throws a relevant exception on failure
|
95
|
+
# Arguments:
|
96
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
97
|
+
# card_nick -- the nickname of the credit card to save
|
98
|
+
# credit_card -- the credit card to save. Should be an Ordrin::Data::CreditCard object
|
99
|
+
def set_credit_card(login, card_nick, credit_card)
|
100
|
+
card_nick = Normalize.normalize(card_nick, :nick)
|
101
|
+
data = credit_card.make_dict
|
102
|
+
data.merge!(login.make_dict)
|
103
|
+
data['nick'] = card_nick
|
104
|
+
return call_api(:put, ['u', login.email, 'ccs', card_nick], login, data)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Remove an credit card, saved by the logged in user, by nickname
|
108
|
+
# Throws a relevant exception on failure.
|
109
|
+
# Arguments:
|
110
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
111
|
+
# card_nick -- the nickname of the credit card to remove
|
112
|
+
def remove_credit_card(login, card_nick)
|
113
|
+
return call_api(:delete, ['u', login.email, 'ccs', Normalize.normalize(card_nick, :nick)], login)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Get a list of previous orders by the logged in user.
|
117
|
+
# Arguments:
|
118
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
119
|
+
def get_order_history(login)
|
120
|
+
return call_api(:get, ['u', login.email, 'orders'], login)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get details of a particular previous order by the logged in user.
|
124
|
+
# Arguments:
|
125
|
+
# login -- the user's login information. Should be an Ordrin::Data::UserLogin object
|
126
|
+
# order_id -- The order ID
|
127
|
+
def get_order_detail(login, order_id)
|
128
|
+
return call_api(:get, ['u', login.email, 'orders', Normalize.normalize(order_id, :alphanum)], login)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Change the logged in user's password.
|
132
|
+
# Arguments:
|
133
|
+
# login -- the user's current login information. Should be an Ordrin::Data::UserLogin object
|
134
|
+
# new_password -- the new password (in plain text)
|
135
|
+
def set_password(login, new_password)
|
136
|
+
data = {'email' => login.email,
|
137
|
+
'password' => Data::UserLogin.hash_password(new_password),
|
138
|
+
'previous_password' => login.password}
|
139
|
+
return self.call_api(:put, ['u', login.email, 'password'], login, data)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/ordrin.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative 'ordrin/restaurant'
|
2
|
+
require_relative 'ordrin/user'
|
3
|
+
require_relative 'ordrin/order'
|
4
|
+
require_relative 'ordrin/data'
|
5
|
+
|
6
|
+
module Ordrin
|
7
|
+
class APIs
|
8
|
+
|
9
|
+
attr_reader :restaurant, :user, :order
|
10
|
+
|
11
|
+
# Sets up this module to make API calls. The first argument is the developer's
|
12
|
+
# API key. The other three are the URLs corresponding to the three parts of the api.
|
13
|
+
# No API calls will work until this function is called. API objects will only be
|
14
|
+
# instantiated for URLs that are passed in.
|
15
|
+
|
16
|
+
# Arguments:
|
17
|
+
# api_key -- The developer's API key
|
18
|
+
# servers -- How the server URLs should be set. Must be :production, :test, or :custom
|
19
|
+
# restaurant_url -- The base url for the restaurant API. Can only be set if servers==:custom.
|
20
|
+
# user_url -- The base url for the user API. Can only be set if servers==:custom.
|
21
|
+
# order_url -- The base url for the order API. Can only be set if servers==:custom.
|
22
|
+
def initialize(api_key, servers, restaurant_url=nil, user_url=nil, order_url=nil)
|
23
|
+
@api_key = api_key
|
24
|
+
if servers!=:custom
|
25
|
+
unless restaurant_url.nil? and user_url.nil? and order_url.nil?
|
26
|
+
raise ArgumentError.new("Individual URL parameters can only be set if servers is set to :custom")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
if servers==:production
|
30
|
+
restaurant_url = "https://r.ordr.in/"
|
31
|
+
user_url = "https://u.ordr.in/"
|
32
|
+
order_url = "https://o.ordr.in/"
|
33
|
+
elsif servers==:test
|
34
|
+
restaurant_url = "https://r-test.ordr.in/"
|
35
|
+
user_url = "https://u-test.ordr.in/"
|
36
|
+
order_url = "https://o-test.ordr.in/"
|
37
|
+
elsif servers!=:custom
|
38
|
+
raise ArgumentError.new("servers must be set to :production, :test, or :custom")
|
39
|
+
end
|
40
|
+
unless restaurant_url.nil?
|
41
|
+
@restaurant = RestaurantApi.new(api_key, restaurant_url)
|
42
|
+
end
|
43
|
+
unless user_url.nil?
|
44
|
+
@user = UserApi.new(api_key, user_url)
|
45
|
+
end
|
46
|
+
unless order_url.nil?
|
47
|
+
@order = OrderApi.new(api_key, order_url)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def config
|
52
|
+
return {"API key" => api_key,
|
53
|
+
"Restaurant URL" => @restaurant.base_url,
|
54
|
+
"User URL" => @user.base_url,
|
55
|
+
"Order URL" => @order.base_url}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ordrin
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ordr.in
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-06-14 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.7.3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.7.3
|
30
|
+
description: Ordrin API wrapper. Used to simplify making calls to the Ordr.in API
|
31
|
+
in Ruby
|
32
|
+
email:
|
33
|
+
- tech@ordr.in
|
34
|
+
executables:
|
35
|
+
- ordrindemo.rb
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- lib/ordrin.rb
|
40
|
+
- lib/ordrin/data.rb
|
41
|
+
- lib/ordrin/errors.rb
|
42
|
+
- lib/ordrin/normalize.rb
|
43
|
+
- lib/ordrin/order.rb
|
44
|
+
- lib/ordrin/ordrinapi.rb
|
45
|
+
- lib/ordrin/restaurant.rb
|
46
|
+
- lib/ordrin/user.rb
|
47
|
+
- bin/ordrindemo.rb
|
48
|
+
homepage: https://github.com/ordrin/api-ruby
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.8.23
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Ordrin API wrapper
|
72
|
+
test_files: []
|