presto_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c5713fb98d88b077aa5848a8a2dd51ddde039d3d
4
+ data.tar.gz: 03044d222c4672a4016350234be80b8d6efb78c1
5
+ SHA512:
6
+ metadata.gz: 639eb8efdb1b13d527edc04dd9c564d380e967c4735a74f22f15bad92455d5f1aa195e69f3e095728c5be6c39d935014d50c471eb5f9257b60d0504e3884c789
7
+ data.tar.gz: f570924bb8a1b37a7d8088e57060d32fb8fe42397c1850ea00cf6b5f5908e05096b8ecdf566d847ea9562b4aa33f646b630b7551e6928da0280a367b0cf518c9
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ .config
2
+ InstalledFiles
3
+ pkg
4
+ *.gem
5
+ .bundle
6
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 JP Simard
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # The Presto Gem
2
+
3
+ Gem for interacting with [Presto cards](http://prestocard.ca). Currently supports the following features:
4
+
5
+ * Registered and unregistered cards (i.e. username/passwords or card numbers)
6
+ * Card Status
7
+ * Status
8
+ * Balance
9
+ * User Information
10
+ * First Name
11
+ * Last Name
12
+ * Address 1
13
+ * Address 2
14
+ * City
15
+ * Province
16
+ * Country
17
+ * Postal Code
18
+ * Phone Number
19
+ * Email
20
+ * Security Question
21
+ * Security Answer
22
+ * Transaction History
23
+ * Date
24
+ * Service Provider
25
+ * Location
26
+ * Type
27
+ * Amount
28
+ * Balance
29
+ * Loyalty Month
30
+ * Loyalty Trip
31
+ * Loyalty Step
32
+ * Loyalty Discount
33
+
34
+ ## Usage
35
+
36
+ ```ruby
37
+ require 'presto_api'
38
+
39
+ status = PrestoAPI::Client.new.card_status_with_number('XXXXXXXXXXXXXXXXX')
40
+ puts status.balance
41
+ ```
42
+
43
+ ## License
44
+
45
+ MIT Licensed.
46
+
47
+ ## Notice
48
+
49
+ Please respect the Presto website's [Terms and Conditions](https://www.prestocard.ca/en-US/Pages/ContentPages/Terms.aspx).
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require "bundler/setup"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'spec/rake/spectask'
5
+
6
+ Spec::Rake::SpecTask.new("spec") do |t|
7
+ t.spec_files = FileList['spec/**/*_spec.rb']
8
+ t.spec_opts = ['--color']
9
+ end
10
+
11
+ Spec::Rake::SpecTask.new("rcov_spec") do |t|
12
+ t.spec_files = FileList['spec/**/*_spec.rb']
13
+ t.spec_opts = ['--color']
14
+ t.rcov = true
15
+ t.rcov_opts = ['--exclude', '^spec,/gems/']
16
+ end
17
+
18
+ task :test => :spec
19
+
20
+ desc "Run specs as default activity"
21
+ task :default => :spec
@@ -0,0 +1,3 @@
1
+ module PrestoAPI
2
+ VERSION = "0.0.1"
3
+ end
data/lib/presto_api.rb ADDED
@@ -0,0 +1,179 @@
1
+ require 'rubygems'
2
+ require 'mechanize'
3
+
4
+ module PrestoAPI
5
+ class Base
6
+ def to_json
7
+ hash = {}
8
+ self.instance_variables.each do |var|
9
+ # Remove @ symbol from var name
10
+ key = var.to_s[1..-1]
11
+ hash[key] = self.instance_variable_get var
12
+ end
13
+ hash.to_json
14
+ end
15
+
16
+ def from_json! string
17
+ JSON.load(string).each do |var, val|
18
+ self.instance_variable_set var, val
19
+ end
20
+ end
21
+ end
22
+
23
+ class CardStatus < Base
24
+ attr_accessor :balance, :status
25
+ end
26
+
27
+ class User < Base
28
+ attr_accessor :first_name,
29
+ :last_name,
30
+ :address,
31
+ :apt,
32
+ :city,
33
+ :province,
34
+ :country,
35
+ :postal_code,
36
+ :phone_number,
37
+ :email,
38
+ :security_question,
39
+ :security_answer
40
+ end
41
+
42
+ class Transaction < Base
43
+ attr_accessor :date,
44
+ :service_provider,
45
+ :location,
46
+ :type,
47
+ :amount,
48
+ :balance,
49
+ :loyalty_month,
50
+ :loyalty_trip,
51
+ :loyalty_step,
52
+ :loyalty_discount
53
+ end
54
+
55
+ class Client
56
+ def user_with_username_password(username, password)
57
+ login_with_username_password(username, password)
58
+ user_from_page(agent.get('https://www.prestocard.ca/en-US/Pages/TransactionalPages/ViewUpdateRegistration.aspx'))
59
+ end
60
+
61
+ def transaction_history_with_username_password(username, password)
62
+ login_with_username_password(username, password)
63
+ transaction_history_from_page(agent.get('https://www.prestocard.ca/en-US/Pages/TransactionalPages/TransactionHistory.aspx'))
64
+ end
65
+
66
+ def card_status_with_username_password(username, password)
67
+ card_status_from_page(login_with_username_password(username, password))
68
+ end
69
+
70
+ def card_status_with_number(card_number)
71
+ card_status_from_page(login_with_card_number(card_number))
72
+ end
73
+
74
+ private
75
+
76
+ def login_with_username_password(username, password)
77
+ # Fill out the registered login form
78
+ field_hash = {
79
+ 'ctl00$SPWebPartManager1$AccountLoginWebpartControl$ctl00$webpartRegisteredUserLogin$ctl00$textboxRegisteredLogin' => username,
80
+ 'ctl00$SPWebPartManager1$AccountLoginWebpartControl$ctl00$webpartRegisteredUserLogin$ctl00$textboxPassword' => password
81
+ }
82
+ button_name = 'ctl00$SPWebPartManager1$AccountLoginWebpartControl$ctl00$webpartRegisteredUserLogin$ctl00$buttonSubmit'
83
+ submit_form(login_page.forms.first, field_hash, button_name)
84
+ end
85
+
86
+ def login_with_card_number(card_number)
87
+ # Fill out the anonymous login form
88
+ field_hash = {
89
+ 'ctl00$SPWebPartManager1$AccountLoginWebpartControl$ctl00$webpartAnonymousUserLogin$ctl00$textboxAnonymousLogin' => card_number
90
+ }
91
+ button_name = 'ctl00$SPWebPartManager1$AccountLoginWebpartControl$ctl00$webpartAnonymousUserLogin$ctl00$buttonSubmit'
92
+ submit_form(login_page.forms.first, field_hash, button_name)
93
+ end
94
+
95
+ def login_page
96
+ @login_page ||= agent.get('https://www.prestocard.ca/en-US/Pages/TransactionalPages/AccountLogin.aspx')
97
+ end
98
+
99
+ def submit_form(form, field_hash, button_name)
100
+ field_hash.each do |key, value|
101
+ form.field_with(:name => key).value = value
102
+ end
103
+ button = form.button_with(:name => button_name)
104
+ agent.submit(form, button)
105
+ end
106
+
107
+ def card_status_from_page(page)
108
+ balance = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_AFMSCardSummaryWebpart_ctl00_wizardCardSummary_labelDisplayBalance"]/text()[last()]').last
109
+ status = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_AFMSCardSummaryWebpart_ctl00_wizardCardSummary_labelDisplayCardStatus"]/text()[last()]').last
110
+ if !balance || !status
111
+ puts 'Try logging in with username/password instead of just the card number'
112
+ return nil
113
+ end
114
+ card_status = CardStatus.new
115
+ card_status.status = status.content
116
+ card_status.balance = balance.content
117
+ card_status
118
+ end
119
+
120
+ def user_from_page(page)
121
+ first_name = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelFirstNameOutput"]/text()[last()]').last
122
+ last_name = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelLastNameOutput"]/text()[last()]').last
123
+ address = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelStreetAddress1Output"]/text()[last()]').last
124
+ apt = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelStreetAddress1Output"]/text()[last()]').last
125
+ city = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelCityOutput"]/text()[last()]').last
126
+ province = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelProvinceOutput"]/text()[last()]').last
127
+ country = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelCountryOutput"]/text()[last()]').last
128
+ postal_code = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelPostalCodeOutput"]/text()[last()]').last
129
+ phone_number = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelPrimaryTelephoneNumberOutput"]/text()[last()]').last
130
+ email = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_labelEmailAddressOutput"]/text()[last()]').last
131
+ security_question = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_webPartSecurityDetails_ctl00_labelSecurityQuestionOutput"]/text()[last()]').last
132
+ security_answer = page.parser.xpath('//span[@id="ctl00_SPWebPartManager1_updateRegistrationWebPart_ctl00_WizardViewUpdateProfile_webPartSecurityDetails_ctl00_labelSecurityResponseOutput"]/text()[last()]').last
133
+
134
+ if !first_name
135
+ puts 'There is no user information assigned to this account'
136
+ return nil
137
+ end
138
+
139
+ user = User.new
140
+ user.first_name = first_name.content || ''
141
+ user.last_name = last_name.content || ''
142
+ user.address = address.content || ''
143
+ user.apt = apt.content || ''
144
+ user.city = city.content || ''
145
+ user.province = province.content || ''
146
+ user.country = country.content || ''
147
+ user.postal_code = postal_code.content || ''
148
+ user.phone_number = phone_number.content || ''
149
+ user.email = email.content || ''
150
+ user.security_question = security_question.content || ''
151
+ user.security_answer = security_answer.content || ''
152
+ user
153
+ end
154
+
155
+ def transaction_history_from_page(page)
156
+ number_of_items = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']").children.count
157
+ transaction_history = []
158
+ for i in 2..number_of_items
159
+ transaction = Transaction.new
160
+ transaction.date = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[1]").last.content
161
+ transaction.service_provider = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[2]").last.content
162
+ transaction.location = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[3]").last.content
163
+ transaction.type = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[4]").last.content
164
+ transaction.amount = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[5]").last.content
165
+ transaction.balance = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[6]").last.content
166
+ transaction.loyalty_month = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[7]").last.content
167
+ transaction.loyalty_trip = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[8]").last.content
168
+ transaction.loyalty_step = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[9]").last.content
169
+ transaction.loyalty_discount = page.parser.xpath("//table[@id='ctl00_SPWebPartManager1_CheckTransactionHistoryWebPartControl_ctl00_ViewTransactionHistory_gridTransactionHistory']/tr[#{i}]/td[10]").last.content
170
+ transaction_history.push transaction
171
+ end
172
+ transaction_history
173
+ end
174
+
175
+ def agent
176
+ @agent ||= Mechanize.new
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "presto_api/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "presto_api"
7
+ s.version = PrestoAPI::VERSION
8
+ s.licenses = ['MIT']
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ['JP Simard']
11
+ s.email = ["jp@jpsim.com"]
12
+ s.homepage = "https://github.com/jpsim/presto-gem"
13
+ s.summary = "Gem for interacting with Presto cards."
14
+ s.description = "Gem for interacting with Presto cards, using mechanize."
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "mechanize", "2.7.3"
20
+
21
+ s.add_development_dependency "rake", '~> 0'
22
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: presto_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - JP Simard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mechanize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.7.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.7.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Gem for interacting with Presto cards, using mechanize.
42
+ email:
43
+ - jp@jpsim.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - Gemfile
50
+ - LICENSE
51
+ - README.md
52
+ - Rakefile
53
+ - lib/presto_api.rb
54
+ - lib/presto_api/version.rb
55
+ - presto_api.gemspec
56
+ homepage: https://github.com/jpsim/presto-gem
57
+ licenses:
58
+ - MIT
59
+ metadata: {}
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 2.2.2
77
+ signing_key:
78
+ specification_version: 4
79
+ summary: Gem for interacting with Presto cards.
80
+ test_files: []