ordrin 0.1.4 → 1.0.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.
@@ -1,186 +0,0 @@
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('%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 DELETED
@@ -1,79 +0,0 @@
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
@@ -1,66 +0,0 @@
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
@@ -1,56 +0,0 @@
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 DELETED
@@ -1,142 +0,0 @@
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