annwn_google_wallet 0.1.2
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.
- checksums.yaml +7 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +159 -0
- data/Rakefile +4 -0
- data/google_wallet.gemspec +41 -0
- data/lib/google_wallet/authentication.rb +33 -0
- data/lib/google_wallet/configuration.rb +30 -0
- data/lib/google_wallet/operations/event_ticket/push_class.rb +75 -0
- data/lib/google_wallet/operations/event_ticket/push_object.rb +76 -0
- data/lib/google_wallet/operations/sign_objects.rb +58 -0
- data/lib/google_wallet/resources/base.rb +56 -0
- data/lib/google_wallet/resources/event_ticket/class.rb +85 -0
- data/lib/google_wallet/resources/event_ticket/object.rb +101 -0
- data/lib/google_wallet/version.rb +5 -0
- data/lib/google_wallet.rb +34 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6d9013a890baee11ae7e2caed5be96bc33db97769414fd2e062b16cb26bd87da
|
4
|
+
data.tar.gz: c7cf16325c2f5d5f3626154d13acd75286dc296b018619ba91511694f660788d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 74a719e2f10eb83cd26851ca2ff345c338892b7f45e0912ce38e2d42f2a6f9fc50f4dbc16d27176675285a48c2503a45a4930b8e6b789426116ef5b770ebd567
|
7
|
+
data.tar.gz: bad596df2d564747e5341e120fa8ba613225c1850d91f7362d46d53863a41f0c36bef70a73aec8c3d3c6e984072c1014a9e2f49e27c0b6eb40135d23ce56155d
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Yaro
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
<p align="right">
|
2
|
+
<a href="https://github.com/vergilet/google_wallet"><img align="" src="https://user-images.githubusercontent.com/2478436/51829223-cb05d600-22f5-11e9-9245-bc6e82dcf028.png" width="56" height="56" /></a>
|
3
|
+
<a href="https://rubygems.org/gems/google_wallet"><img align="right" src="https://user-images.githubusercontent.com/2478436/51829691-c55cc000-22f6-11e9-99a5-42f88a8f2a55.png" width="56" height="56" /></a>
|
4
|
+
</p>
|
5
|
+
|
6
|
+
|
7
|
+
<p align="center">
|
8
|
+
<a href="https://rubygems.org/gems/repost">
|
9
|
+
<img width="460" src="https://github.com/vergilet/google_wallet/assets/2478436/5f9c5925-129a-401e-bd46-82e6ae2b2430"></a>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
# GoogleWallet
|
15
|
+
Unofficial Ruby Gem for [Google Wallet API](https://developers.google.com/wallet).
|
16
|
+
|
17
|
+
## Prerequisites
|
18
|
+
Before you use the Google Wallet API for an integration, complete first four steps from [this guide](https://developers.google.com/wallet/tickets/events/web/prerequisites).
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
*The 1st step will provide you with **IssuerID**=33880000000XXXXXXXX and*
|
23
|
+
|
24
|
+
*on the 3rd step you are going to obtain **key.json**, those are needed for the gem initialization.*
|
25
|
+
|
26
|
+
## Installation
|
27
|
+
|
28
|
+
Add this line to your application's Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem 'google_wallet'
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle install
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install google_wallet
|
41
|
+
|
42
|
+
## Usage
|
43
|
+
|
44
|
+
Create initializer:
|
45
|
+
```ruby
|
46
|
+
# config/initializers/google_wallet.rb
|
47
|
+
|
48
|
+
GoogleWallet.configure do |config|
|
49
|
+
config.load_credentials_from_file('./key.json')
|
50
|
+
config.issuer_id = '33880000000XXXXXXXX'
|
51
|
+
config.debug_mode = true
|
52
|
+
config.logger = Logger.new(STDOUT)
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
### EventTicket
|
57
|
+
|
58
|
+
#### Create class (event representation):
|
59
|
+
```ruby
|
60
|
+
event_attributes = {
|
61
|
+
# required fields
|
62
|
+
class_identifier: 'Event-123456',
|
63
|
+
event_name: 'Solo Singing Contest #1 Yay!',
|
64
|
+
issuer_name: 'iChar System',
|
65
|
+
|
66
|
+
# other fields
|
67
|
+
event_id: '123456',
|
68
|
+
logo_url: 'https://images.unsplash.com/photo-1475721027785-f74eccf877e2?auto=format&fit=crop&w=360&h=360',
|
69
|
+
hero_image_url: 'https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?auto=format&fit=crop&w=1032&h=336',
|
70
|
+
homepage_url: 'https://example.com',
|
71
|
+
country_code: 'no',
|
72
|
+
venue_name: 'Opera Theater',
|
73
|
+
venue_address: "Shevchenka street 41/5, Ukraine, Kyiv",
|
74
|
+
start_date_time: '2023-09-27T22:30',
|
75
|
+
end_date_time: '2023-09-28T01:30',
|
76
|
+
hex_background_color: '#ff0077',
|
77
|
+
callback_url: 'https://example.com/gpass_callback'
|
78
|
+
}
|
79
|
+
|
80
|
+
|
81
|
+
# Create Resource of EventTicket Class
|
82
|
+
event = GoogleWallet::Resources::EventTicket::Class.new(attributes: event_attributes)
|
83
|
+
|
84
|
+
# Push Class to Google Wallet API
|
85
|
+
event.push
|
86
|
+
```
|
87
|
+
|
88
|
+
#### Create object (ticket representation):
|
89
|
+
```ruby
|
90
|
+
ticket_attributes = {
|
91
|
+
# required fields
|
92
|
+
object_identifier: 'fd9b637f-0381-42ad-9161-b4d887d79d9f',
|
93
|
+
class_identifier: 'Event-123456',
|
94
|
+
|
95
|
+
# other fields
|
96
|
+
grouping_id: 'order-12345',
|
97
|
+
ticket_type: 'VIP Adult Plus',
|
98
|
+
section: 'The Sponsor Felt-F Overpower',
|
99
|
+
seat: '65',
|
100
|
+
row: '17',
|
101
|
+
gate: 'G3, G4',
|
102
|
+
ticket_holder_name: 'Yaro Developer',
|
103
|
+
qr_code_value: '12345678',
|
104
|
+
ticket_number: 'cdeqw',
|
105
|
+
valid_time_start: '2023-09-27T22:30',
|
106
|
+
valid_time_end: '2023-09-28T02:00',
|
107
|
+
micros: 82_000_000,
|
108
|
+
currency_code: 'NOK',
|
109
|
+
hex_background_color: '#0090ff'
|
110
|
+
}
|
111
|
+
|
112
|
+
# Create Resource of EventTicket Object
|
113
|
+
ticket = GoogleWallet::Resources::EventTicket::Object.new(attributes: ticket_attributes)
|
114
|
+
|
115
|
+
# Push Object to Google Wallet API
|
116
|
+
|
117
|
+
# Option 1 (Recommended):
|
118
|
+
# Separated push and sign
|
119
|
+
ticket.push
|
120
|
+
jwt = ticket.sign(push_resource: false)
|
121
|
+
|
122
|
+
# Option 2:
|
123
|
+
# Combined - just use sign
|
124
|
+
jwt = ticket.sign # default is push_resource: true
|
125
|
+
|
126
|
+
# visit output link via authenticated browser
|
127
|
+
# or send it to you android device with Wallet app.
|
128
|
+
"https://pay.google.com/gp/v/save/#{jwt}"
|
129
|
+
|
130
|
+
```
|
131
|
+
|
132
|
+
#### Separation of Ticket Push and JWT Signing
|
133
|
+
The gem offers a distinct advantage when pushing tickets separately from the signing phase. If tickets are pushed individually, the subsequent signing method utilizes only the ticket identifiers during the JWT signing process, rather than the entire ticket objects.
|
134
|
+
|
135
|
+
*Advantages of Using Ticket Identifiers:*
|
136
|
+
|
137
|
+
*By employing ticket identifiers in the signing process instead of the full ticket objects, it significantly reduces the length of the final link generated. This streamlined approach allows for a more efficient and concise link that can be easily sent to the user.*
|
138
|
+
|
139
|
+
|
140
|
+
### Result
|
141
|
+
|
142
|
+
<p align="center">
|
143
|
+
<img src="https://github.com/vergilet/google_wallet/assets/2478436/394dc017-c6f8-43d1-ad7b-f2139d643aec"></a>
|
144
|
+
</p>
|
145
|
+
|
146
|
+
|
147
|
+
## Development
|
148
|
+
|
149
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
150
|
+
|
151
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
152
|
+
|
153
|
+
## Contributing
|
154
|
+
|
155
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/vergilet/google_wallet.
|
156
|
+
|
157
|
+
## License
|
158
|
+
|
159
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/google_wallet/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "annwn_google_wallet"
|
7
|
+
spec.version = GoogleWallet::VERSION
|
8
|
+
spec.authors = ["luis"]
|
9
|
+
spec.email = ["luis@annwn.app"]
|
10
|
+
|
11
|
+
spec.summary = "google wallet"
|
12
|
+
spec.description = "google wallet"
|
13
|
+
spec.homepage = "https://github.com/colmex/google_wallet"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/colmex/google_wallet"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/colmex/google_wallet/releases"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
# Uncomment to register a new dependency of your gem
|
33
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
34
|
+
|
35
|
+
# For more information and examples about making a new gem, check out our
|
36
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
37
|
+
|
38
|
+
spec.add_dependency 'httparty'
|
39
|
+
spec.add_dependency 'jwt'
|
40
|
+
spec.add_dependency 'googleauth'
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# lib/google_wallet/authentication.rb
|
2
|
+
|
3
|
+
require 'googleauth'
|
4
|
+
|
5
|
+
module GoogleWallet
|
6
|
+
class Authentication
|
7
|
+
SCOPE = 'https://www.googleapis.com/auth/wallet_object.issuer'
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@credentials = GoogleWallet.configuration.json_credentials
|
11
|
+
end
|
12
|
+
|
13
|
+
def access_token
|
14
|
+
if @credentials
|
15
|
+
begin
|
16
|
+
credentials = Google::Auth::ServiceAccountCredentials.make_creds(
|
17
|
+
json_key_io: StringIO.new(@credentials.to_json),
|
18
|
+
scope: SCOPE
|
19
|
+
)
|
20
|
+
|
21
|
+
credentials.fetch_access_token!
|
22
|
+
credentials.access_token
|
23
|
+
rescue StandardError => e
|
24
|
+
puts "Error while fetching access token: #{e.message}"
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
else
|
28
|
+
puts "No credentials provided."
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# google_wallet/configuration.rb
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module GoogleWallet
|
6
|
+
class Configuration
|
7
|
+
attr_accessor :json_credentials, :issuer_id, :api_endpoint, :debug_mode, :logger
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@api_endpoint = 'https://walletobjects.googleapis.com/walletobjects/v1'
|
11
|
+
@json_credentials = nil
|
12
|
+
@issuer_id = nil
|
13
|
+
@debug_mode = false
|
14
|
+
@logger = Logger.new(STDOUT)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.logger
|
18
|
+
@logger
|
19
|
+
end
|
20
|
+
|
21
|
+
def load_credentials_from_file(file_path)
|
22
|
+
begin
|
23
|
+
json_data = JSON.parse(File.read(file_path))
|
24
|
+
@json_credentials = json_data
|
25
|
+
rescue JSON::ParserError, Errno::ENOENT => e
|
26
|
+
raise "Error loading JSON credentials from file: #{e.message}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
module GoogleWallet
|
6
|
+
module Operations
|
7
|
+
module EventTicket
|
8
|
+
class PushClass
|
9
|
+
ENDPOINT = 'eventTicketClass'
|
10
|
+
|
11
|
+
def initialize(resource:, access_token:)
|
12
|
+
@resource = resource
|
13
|
+
@access_token = access_token
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
return update_class if exists?
|
18
|
+
create_class
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :resource, :access_token
|
24
|
+
|
25
|
+
def exists?
|
26
|
+
response = HTTParty.get(
|
27
|
+
"#{GoogleWallet.configuration.api_endpoint}/#{ENDPOINT}/#{resource.id}",
|
28
|
+
query: { access_token: access_token }
|
29
|
+
)
|
30
|
+
|
31
|
+
if GoogleWallet.debug_mode?
|
32
|
+
GoogleWallet.logger.debug(self.class.name)
|
33
|
+
GoogleWallet.logger.debug(__method__)
|
34
|
+
GoogleWallet.logger.debug(response.inspect)
|
35
|
+
end
|
36
|
+
|
37
|
+
response.success?
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_class
|
41
|
+
response = HTTParty.post(
|
42
|
+
"#{GoogleWallet.configuration.api_endpoint}/#{ENDPOINT}",
|
43
|
+
query: { access_token: access_token },
|
44
|
+
body: resource.attributes.to_json,
|
45
|
+
headers: { 'Content-Type' => 'application/json' }
|
46
|
+
)
|
47
|
+
if GoogleWallet.debug_mode?
|
48
|
+
GoogleWallet.logger.debug(self.class.name)
|
49
|
+
GoogleWallet.logger.debug(__method__)
|
50
|
+
GoogleWallet.logger.debug(response.inspect)
|
51
|
+
end
|
52
|
+
|
53
|
+
response.success?
|
54
|
+
end
|
55
|
+
|
56
|
+
def update_class
|
57
|
+
response = HTTParty.put(
|
58
|
+
"#{GoogleWallet.configuration.api_endpoint}/#{ENDPOINT}/#{resource.id}",
|
59
|
+
query: {access_token: access_token},
|
60
|
+
body: resource.attributes.to_json,
|
61
|
+
headers: { 'Content-Type' => 'application/json' }
|
62
|
+
)
|
63
|
+
|
64
|
+
if GoogleWallet.debug_mode?
|
65
|
+
GoogleWallet.logger.debug(self.class.name)
|
66
|
+
GoogleWallet.logger.debug(__method__)
|
67
|
+
GoogleWallet.logger.debug(response.inspect)
|
68
|
+
end
|
69
|
+
|
70
|
+
response.success?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
module GoogleWallet
|
6
|
+
module Operations
|
7
|
+
module EventTicket
|
8
|
+
class PushObject
|
9
|
+
ENDPOINT = 'eventTicketObject'
|
10
|
+
|
11
|
+
def initialize(resource:, access_token:)
|
12
|
+
@resource = resource
|
13
|
+
@access_token = access_token
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
return update_class if exists?
|
18
|
+
create_class
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :resource, :access_token
|
24
|
+
|
25
|
+
def exists?
|
26
|
+
response = HTTParty.get(
|
27
|
+
"#{GoogleWallet.configuration.api_endpoint}/#{ENDPOINT}/#{resource.id}",
|
28
|
+
query: { access_token: access_token }
|
29
|
+
)
|
30
|
+
|
31
|
+
if GoogleWallet.debug_mode?
|
32
|
+
GoogleWallet.logger.debug(self.class.name)
|
33
|
+
GoogleWallet.logger.debug(__method__)
|
34
|
+
GoogleWallet.logger.debug(response.inspect)
|
35
|
+
end
|
36
|
+
|
37
|
+
response.success?
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_class
|
41
|
+
response = HTTParty.post(
|
42
|
+
"#{GoogleWallet.configuration.api_endpoint}/#{ENDPOINT}",
|
43
|
+
query: { access_token: access_token },
|
44
|
+
body: resource.attributes.to_json,
|
45
|
+
headers: { 'Content-Type' => 'application/json' }
|
46
|
+
)
|
47
|
+
|
48
|
+
if GoogleWallet.debug_mode?
|
49
|
+
GoogleWallet.logger.debug(self.class.name)
|
50
|
+
GoogleWallet.logger.debug(__method__)
|
51
|
+
GoogleWallet.logger.debug(response.inspect)
|
52
|
+
end
|
53
|
+
|
54
|
+
response.success?
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_class
|
58
|
+
response = HTTParty.put(
|
59
|
+
"#{GoogleWallet.configuration.api_endpoint}/#{ENDPOINT}/#{resource.id}",
|
60
|
+
query: {access_token: access_token},
|
61
|
+
body: resource.attributes.to_json,
|
62
|
+
headers: { 'Content-Type' => 'application/json' }
|
63
|
+
)
|
64
|
+
|
65
|
+
if GoogleWallet.debug_mode?
|
66
|
+
GoogleWallet.logger.debug(self.class.name)
|
67
|
+
GoogleWallet.logger.debug(__method__)
|
68
|
+
GoogleWallet.logger.debug(response.inspect)
|
69
|
+
end
|
70
|
+
|
71
|
+
response.success?
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jwt'
|
4
|
+
|
5
|
+
module GoogleWallet
|
6
|
+
module Operations
|
7
|
+
class SignObjects
|
8
|
+
attr_reader :jwt, :resources, :resource_ids, :objects_type
|
9
|
+
DEFAULT_OBJECTS_TYPE = 'genericObjects'
|
10
|
+
|
11
|
+
def initialize(resources: [], resource_ids: [], objects_type: DEFAULT_OBJECTS_TYPE)
|
12
|
+
@resources = resources.kind_of?(Array) ? resources : [resources]
|
13
|
+
@resource_ids = resource_ids.kind_of?(Array) ? resource_ids : [resource_ids]
|
14
|
+
@objects_type = objects_type
|
15
|
+
unless resource_ids.empty?
|
16
|
+
GoogleWallet.logger.info("You didn't provide objects_type, fallback to use default #{DEFAULT_OBJECTS_TYPE}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def call
|
21
|
+
payload = {
|
22
|
+
iss: GoogleWallet.configuration.json_credentials["client_email"],
|
23
|
+
aud: 'google',
|
24
|
+
typ: 'savetowallet',
|
25
|
+
payload: objects_payload,
|
26
|
+
origins: []
|
27
|
+
}
|
28
|
+
|
29
|
+
@jwt = JWT.encode(payload, rsa_private_key, 'RS256')
|
30
|
+
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def objects_payload
|
37
|
+
objects.merge(object_ids) { |_key, old_val, new_val| old_val + new_val }
|
38
|
+
end
|
39
|
+
|
40
|
+
def objects
|
41
|
+
@objects ||= resources.each_with_object({}) do |resource, memo|
|
42
|
+
memo[resource.payload_key.to_sym] ||= []
|
43
|
+
memo[resource.payload_key.to_sym] << resource.attributes
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def object_ids
|
48
|
+
return {} if resource_ids.empty?
|
49
|
+
|
50
|
+
{ objects_type.to_sym => resource_ids.map { |resource_id| { id: resource_id } } }
|
51
|
+
end
|
52
|
+
|
53
|
+
def rsa_private_key
|
54
|
+
@rsa_private_key ||= OpenSSL::PKey::RSA.new(GoogleWallet.configuration.json_credentials["private_key"])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoogleWallet
|
4
|
+
module Resources
|
5
|
+
class Base
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(attributes: {}, options: {})
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
attributes.each do |key, value|
|
12
|
+
instance_variable_set("@#{key}", value)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def attributes
|
17
|
+
hash = deep_merge(template, options)
|
18
|
+
remove_empty_values(hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
def payload_key
|
22
|
+
raise 'Define in resource'
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def payload_key_logic
|
28
|
+
self.class.name.split("::")[-2].tap { |obj| obj[0] = obj[0].downcase }
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_fields(fields = [])
|
32
|
+
fields.each do |field|
|
33
|
+
raise "#{self.class.name} - #{field} is required" if blank?(instance_variable_get("@#{field}"))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def deep_merge(hash1, hash2)
|
38
|
+
hash1.merge(hash2) do |_key, old_val, new_val|
|
39
|
+
old_val.is_a?(Hash) && new_val.is_a?(Hash) ? deep_merge(old_val, new_val) : new_val
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def remove_empty_values(hash)
|
44
|
+
hash.reject { |_key, value| value.nil? || value == '' || value == {} }
|
45
|
+
end
|
46
|
+
|
47
|
+
def blank?(value)
|
48
|
+
value.nil? || value.to_s.strip.empty?
|
49
|
+
end
|
50
|
+
|
51
|
+
def present?(value)
|
52
|
+
!blank?(value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoogleWallet
|
4
|
+
module Resources
|
5
|
+
module EventTicket
|
6
|
+
class Class < Base
|
7
|
+
attr_reader :class_identifier, :issuer_name, :logo_url, :event_id, :event_name,
|
8
|
+
:venue_name, :venue_address, :start_date_time, :end_date_time, :country_code,
|
9
|
+
:hex_background_color, :hero_image_url, :homepage_url, :callback_url, :id
|
10
|
+
|
11
|
+
|
12
|
+
# attributes = {
|
13
|
+
# class_identifier: 'Event-1234',
|
14
|
+
# issuer_name: 'iChar System',
|
15
|
+
# event_name: 'Solo Singing Contest #1 Yay!',
|
16
|
+
# event_id: '123456',
|
17
|
+
# logo_url: 'https://images.unsplash.com/photo-1475721027785-f74eccf877e2?auto=format&fit=crop&w=360&h=360',
|
18
|
+
# hero_image_url: 'https://images.unsplash.com/photo-1501281668745-f7f57925c3b4?auto=format&fit=crop&w=1032&h=336'
|
19
|
+
# homepage_url: 'https://arrangement.ticketco.events',
|
20
|
+
# country_code: 'no',
|
21
|
+
# venue_name: 'Opera Theater',
|
22
|
+
# venue_address: "Shevchenka street 41/5, Ukraine, Lviv",
|
23
|
+
# start_date_time: '2023-08-27T22:30',
|
24
|
+
# end_date_time: '2023-08-28T01:30',
|
25
|
+
# hex_background_color: '#ff0077',
|
26
|
+
# callback_url: 'https://example.com/gpass_callback'
|
27
|
+
# }
|
28
|
+
|
29
|
+
|
30
|
+
def initialize(attributes: {}, options: {})
|
31
|
+
super
|
32
|
+
validate_fields( %w[class_identifier event_name issuer_name])
|
33
|
+
@id = "#{GoogleWallet.configuration.issuer_id}.#{@class_identifier}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def push
|
37
|
+
access_token = GoogleWallet::Authentication.new.access_token
|
38
|
+
GoogleWallet::Operations::EventTicket::PushClass.new(resource: self, access_token: access_token).call
|
39
|
+
end
|
40
|
+
|
41
|
+
def sign(push_resource: true)
|
42
|
+
raise "Class cannot be signed without Object,
|
43
|
+
use GoogleWallet::Operations::SignObjects.new(...)
|
44
|
+
to create/modify simultaneously classes and objects by following jwt link"
|
45
|
+
end
|
46
|
+
|
47
|
+
def payload_key
|
48
|
+
"#{payload_key_logic}Classes"
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def template
|
54
|
+
template = {}
|
55
|
+
|
56
|
+
template[:id] = id
|
57
|
+
template[:issuerName] = issuer_name
|
58
|
+
template[:eventName] = { defaultValue: { language: "en-US", value: event_name } }
|
59
|
+
template[:reviewStatus] = "UNDER_REVIEW"
|
60
|
+
|
61
|
+
template[:eventId] = event_id if present?(event_id)
|
62
|
+
template[:logo] = { sourceUri: { uri: logo_url } } if present?(logo_url)
|
63
|
+
template[:heroImage] = { sourceUri: { uri: hero_image_url } } if present?(hero_image_url)
|
64
|
+
|
65
|
+
template[:homepageUri] = { uri: homepage_url, description: 'Homepage' } if present?(homepage_url)
|
66
|
+
template[:countryCode] = country_code if present?(country_code)
|
67
|
+
template[:hexBackgroundColor] = hex_background_color if present?(hex_background_color)
|
68
|
+
template[:callbackOptions] = { url: callback_url } if present?(callback_url)
|
69
|
+
|
70
|
+
template[:securityAnimation] = { animationType: "FOIL_SHIMMER" }
|
71
|
+
|
72
|
+
template[:venue] = {}
|
73
|
+
template[:venue][:name] = { defaultValue: { language: "en-US", value: venue_name } } if present?(venue_name)
|
74
|
+
template[:venue][:address] = { defaultValue: { language: "en-US", value: venue_address } } if present?(venue_address)
|
75
|
+
|
76
|
+
template[:dateTime] = {}
|
77
|
+
template[:dateTime][:start] = start_date_time if present?(start_date_time)
|
78
|
+
template[:dateTime][:end] = end_date_time if present?(end_date_time)
|
79
|
+
|
80
|
+
template
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GoogleWallet
|
4
|
+
module Resources
|
5
|
+
module EventTicket
|
6
|
+
class Object < Base
|
7
|
+
|
8
|
+
attr_reader :object_identifier, :class_identifier, :seat, :row, :section, :gate,
|
9
|
+
:ticket_type, :grouping_id, :qr_code_value, :qr_code_label, :ticket_holder_name,
|
10
|
+
:valid_time_start, :valid_time_end, :micros, :currency_code,
|
11
|
+
:hex_background_color, :ticket_number, :id, :class_id, :options
|
12
|
+
|
13
|
+
|
14
|
+
# attributes = {
|
15
|
+
# object_identifier: 'fd9b637f-0381-42ad-9161-b4d887d79d9f',
|
16
|
+
# class_identifier: 'Event-1234',
|
17
|
+
# grouping_id: 'order-12345',
|
18
|
+
# ticket_type: 'Vip Pass + Priority24',
|
19
|
+
# section: 'The Sponsor Felt-F Overpower',
|
20
|
+
# seat: '65',
|
21
|
+
# row: '17',
|
22
|
+
# gate: 'G3, G4',
|
23
|
+
# ticket_holder_name: 'Yaro Developer',
|
24
|
+
# qr_code_value: '12345678',
|
25
|
+
# qr_code_label: '12345678',
|
26
|
+
# ticket_number: 'cdeqw',
|
27
|
+
# valid_time_start: '2023-09-27T22:30',
|
28
|
+
# valid_time_end: '2023-09-28T02:00',
|
29
|
+
# micros: 82_000_000,
|
30
|
+
# currency_code: 'NOK',
|
31
|
+
# hex_background_color: '#45ffaa'
|
32
|
+
# }
|
33
|
+
|
34
|
+
def initialize(attributes: {}, options: {})
|
35
|
+
super
|
36
|
+
|
37
|
+
validate_fields( %w[object_identifier class_identifier])
|
38
|
+
@id = "#{GoogleWallet.configuration.issuer_id}.#{@object_identifier}"
|
39
|
+
@class_id = "#{GoogleWallet.configuration.issuer_id}.#{@class_identifier}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def push
|
43
|
+
access_token = GoogleWallet::Authentication.new.access_token
|
44
|
+
GoogleWallet::Operations::EventTicket::PushObject.new(resource: self, access_token: access_token).call
|
45
|
+
end
|
46
|
+
|
47
|
+
def sign(push_resource: true)
|
48
|
+
sign_operation =
|
49
|
+
if push_resource
|
50
|
+
push
|
51
|
+
GoogleWallet::Operations::SignObjects.new(resource_ids: [id], objects_type: self.payload_key)
|
52
|
+
else
|
53
|
+
GoogleWallet::Operations::SignObjects.new(resources: [itself])
|
54
|
+
end
|
55
|
+
|
56
|
+
sign_operation.call
|
57
|
+
sign_operation.jwt
|
58
|
+
end
|
59
|
+
|
60
|
+
def payload_key
|
61
|
+
"#{payload_key_logic}Objects"
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def template
|
67
|
+
template = {}
|
68
|
+
|
69
|
+
template[:id] = id
|
70
|
+
template[:classId] = class_id
|
71
|
+
template[:state] = "ACTIVE"
|
72
|
+
|
73
|
+
template[:ticketType] = { defaultValue: { language: "en-us", value: ticket_type } } if present?(ticket_type)
|
74
|
+
template[:groupingInfo] = { groupingId: grouping_id } if present?(grouping_id)
|
75
|
+
template[:barcode] = { type: "QR_CODE", value: qr_code_value, alternateText: qr_code_label } if present?(qr_code_value)
|
76
|
+
template[:faceValue] = { micros: micros, currencyCode: currency_code } if present?(micros) && present?(currency_code)
|
77
|
+
|
78
|
+
template[:seatInfo] = {}
|
79
|
+
template[:seatInfo][:seat] = { defaultValue: { language: "en-us", value: seat } } if present?(seat)
|
80
|
+
template[:seatInfo][:row] = { defaultValue: { language: "en-us", value: row } } if present?(row)
|
81
|
+
template[:seatInfo][:section] = { defaultValue: { language: "en-us", value: section } } if present?(section)
|
82
|
+
template[:seatInfo][:gate] = { defaultValue: { language: "en-us", value: gate } } if present?(gate)
|
83
|
+
|
84
|
+
template[:validTimeInterval] = {}
|
85
|
+
template[:validTimeInterval][:start] = { date: valid_time_start } if present?(valid_time_start)
|
86
|
+
template[:validTimeInterval][:end] = { date: valid_time_end } if present?(valid_time_end)
|
87
|
+
|
88
|
+
template[:hexBackgroundColor] = hex_background_color if present?(hex_background_color)
|
89
|
+
template[:ticketHolderName] = ticket_holder_name if present?(ticket_holder_name)
|
90
|
+
template[:ticketNumber] = ticket_number if present?(ticket_number)
|
91
|
+
|
92
|
+
puts "\n\n\n\n\n\n\n\n\n"
|
93
|
+
puts template
|
94
|
+
puts "\n\n\n\n\n\n\n\n\n"
|
95
|
+
|
96
|
+
template
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "google_wallet/version"
|
4
|
+
require_relative "google_wallet/configuration"
|
5
|
+
require_relative "google_wallet/authentication"
|
6
|
+
|
7
|
+
require_relative "google_wallet/resources/base"
|
8
|
+
require_relative "google_wallet/resources/event_ticket/class"
|
9
|
+
require_relative "google_wallet/resources/event_ticket/object"
|
10
|
+
|
11
|
+
require_relative "google_wallet/operations/sign_objects"
|
12
|
+
require_relative "google_wallet/operations/event_ticket/push_class"
|
13
|
+
require_relative "google_wallet/operations/event_ticket/push_object"
|
14
|
+
|
15
|
+
module GoogleWallet
|
16
|
+
class Error < StandardError; end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.configure
|
23
|
+
self.configuration ||= Configuration.new
|
24
|
+
yield(configuration)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.logger
|
28
|
+
configuration.logger
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.debug_mode?
|
32
|
+
configuration.debug_mode
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: annwn_google_wallet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- luis
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-03-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jwt
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: googleauth
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: google wallet
|
56
|
+
email:
|
57
|
+
- luis@annwn.app
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- Gemfile
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- Rakefile
|
66
|
+
- google_wallet.gemspec
|
67
|
+
- lib/google_wallet.rb
|
68
|
+
- lib/google_wallet/authentication.rb
|
69
|
+
- lib/google_wallet/configuration.rb
|
70
|
+
- lib/google_wallet/operations/event_ticket/push_class.rb
|
71
|
+
- lib/google_wallet/operations/event_ticket/push_object.rb
|
72
|
+
- lib/google_wallet/operations/sign_objects.rb
|
73
|
+
- lib/google_wallet/resources/base.rb
|
74
|
+
- lib/google_wallet/resources/event_ticket/class.rb
|
75
|
+
- lib/google_wallet/resources/event_ticket/object.rb
|
76
|
+
- lib/google_wallet/version.rb
|
77
|
+
homepage: https://github.com/colmex/google_wallet
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata:
|
81
|
+
homepage_uri: https://github.com/colmex/google_wallet
|
82
|
+
source_code_uri: https://github.com/colmex/google_wallet
|
83
|
+
changelog_uri: https://github.com/colmex/google_wallet/releases
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.6.0
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubygems_version: 3.3.26
|
100
|
+
signing_key:
|
101
|
+
specification_version: 4
|
102
|
+
summary: google wallet
|
103
|
+
test_files: []
|