diff --git a/templates/README.md b/templates/README.md deleted file mode 100644 index 14aed48..0000000 --- a/templates/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Code Generation Code Only - -This directory contains files for generating the demos -found in the parent directory. It does not contain -functioning samples for Google Wallet, so do not -use it as such. \ No newline at end of file diff --git a/templates/generate.py b/templates/generate.py deleted file mode 100644 index be4f21a..0000000 --- a/templates/generate.py +++ /dev/null @@ -1,466 +0,0 @@ -# -# Copyright 2022 Google Inc. All rights reserved. -# -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. -# - -import os, json - -default_class_payload = { - "id": "$class_id", -} - -default_object_payload = { - "id": "$object_id", - "classId": "$class_id", - "state": "ACTIVE", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg" - }, - "contentDescription": { - "defaultValue": { - "language": "en-US", - "value": "Hero image description" - } - } - }, - "textModulesData": [ - { - "header": "Text module header", - "body": "Text module body", - "id": "TEXT_MODULE_ID" - } - ], - "linksModuleData": { - "uris": [ - { - "uri": "http://maps.google.com/", - "description": "Link module URI description", - "id": "LINK_MODULE_URI_ID" - }, - { - "uri": "tel:6505555555", - "description": "Link module tel description", - "id": "LINK_MODULE_TEL_ID" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "sourceUri": { - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg" - }, - "contentDescription": { - "defaultValue": { - "language": "en-US", - "value": "Image module description" - } - } - }, - "id": "IMAGE_MODULE_ID" - } - ], - "barcode": { - "type": "QR_CODE", - "value": "QR code" - } -} - -payloads = {} - -for object_type in ["generic", "offer", "loyalty", "giftCard", "eventTicket", "flight", "transit"]: - payloads[object_type] = { - "$class_payload": dict(default_class_payload), - "$object_payload": dict(default_object_payload), - } - -################# -# Generic -################# - -payloads["generic"]["$object_payload"].update({ - "cardTitle": { - "defaultValue": { - "language": "en-US", - "value": "Generic card title" - } - }, - "header": { - "defaultValue": { - "language": "en-US", - "value": "Generic header" - } - }, - "hexBackgroundColor": "#4285f4", - "logo": { - "sourceUri": { - "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" - }, - "contentDescription": { - "defaultValue": { - "language": "en-US", - "value": "Generic card logo" - } - } - } -}) - -################# -# Offer -################# - -payloads["offer"]["$class_payload"].update({ - "issuerName": "Issuer name", - "reviewStatus": "UNDER_REVIEW", - "provider": "Provider name", - "title": "Offer title", - "redemptionChannel": "ONLINE" -}) - -payloads["offer"]["$object_payload"].update({ - "locations": [ - { - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ], - "validTimeInterval": { - "start": { - "date": "2023-06-12T23:20:50.52Z" - }, - "end": { - "date": "2023-12-12T23:20:50.52Z" - } - } -}) - -################# -# Loyalty -################# - -payloads["loyalty"]["$class_payload"].update({ - "issuerName": "Issuer name", - "reviewStatus": "UNDER_REVIEW", - "programName": "Program name", - "programLogo": { - "sourceUri": { - "uri": "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg" - }, - "contentDescription": { - "defaultValue": { - "language": "en-US", - "value": "Logo description" - } - } - } -}) - -payloads["loyalty"]["$object_payload"].update({ - "locations": [ - { - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ], - "accountId": "Account id", - "accountName": "Account name", - "loyaltyPoints": { - "label": "Points", - "balance": { - "int": 800 - } - } -}) - -################# -# GiftCard -################# - -payloads["giftCard"]["$class_payload"].update({ - "issuerName": "Issuer name", - "reviewStatus": "UNDER_REVIEW", -}) - -payloads["giftCard"]["$object_payload"].update({ - "locations": [ - { - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ], - "cardNumber": "Card number", - "pin": "1234", - "balance": { - "micros": 20000000, - "currencyCode": "USD" - }, - "balanceUpdateTime": { - "date": "2020-04-12T16:20:50.52-04:00" - } -}) - -################# -# Eventticket -################# - -payloads["eventTicket"]["$class_payload"].update({ - "eventId": "EVENT_ID", - "eventName": { - "defaultValue": { - "language": "en-US", - "value": "Event name" - } - }, - "issuerName": "Issuer name", - "reviewStatus": "UNDER_REVIEW" -}) - -payloads["eventTicket"]["$object_payload"].update({ - "locations": [ - { - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ], - "seatInfo": { - "seat": { - "defaultValue": { - "language": "en-US", - "value": "42" - } - }, - "row": { - "defaultValue": { - "language": "en-US", - "value": "G3" - } - }, - "section": { - "defaultValue": { - "language": "en-US", - "value": "5" - } - }, - "gate": { - "defaultValue": { - "language": "en-US", - "value": "A" - } - } - }, - "ticketHolderName": "Ticket holder name", - "ticketNumber": "Ticket number" -}) - -################# -# Flight -################# - -payloads["flight"]["$class_payload"].update({ - "issuerName": "Issuer name", - "reviewStatus": "UNDER_REVIEW", - "localScheduledDepartureDateTime": "2023-07-02T15:30:00", - "flightHeader": { - "carrier": { - "carrierIataCode": "LX" - }, - "flightNumber": "123" - }, - "origin": { - "airportIataCode": "LAX", - "terminal": "1", - "gate": "A2" - }, - "destination": { - "airportIataCode": "SFO", - "terminal": "2", - "gate": "C3" - } -}) - -payloads["flight"]["$object_payload"].update({ - "locations": [ - { - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ], - "passengerName": "Passenger name", - "boardingAndSeatingInfo": { - "boardingGroup": "B", - "seatNumber": "42" - }, - "reservationInfo": { - "confirmationCode": "Confirmation code" - } -}) - -################# -# Transit -################# - -payloads["transit"]["$class_payload"].update({ - "issuerName": "Issuer name", - "reviewStatus": "UNDER_REVIEW", - "logo": { - "sourceUri": { - "uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png" - }, - "contentDescription": { - "defaultValue": { - "language": "en-US", - "value": "Logo description" - } - } - }, - "transitType": "BUS" -}) - -payloads["transit"]["$object_payload"].update({ - "locations": [ - { - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ], - "passengerType": "SINGLE_PASSENGER", - "passengerNames": "Passenger names", - "tripType": "ONE_WAY", - "ticketLeg": { - "originStationCode": "LA", - "originName": { - "defaultValue": { - "language": "en-US", - "value": "Origin name" - } - }, - "destinationStationCode": "SFO", - "destinationName": { - "defaultValue": { - "language": "en-US", - "value": "Destination name" - } - }, - "departureDateTime": "2020-04-12T16:20:50.52Z", - "arrivalDateTime": "2020-04-12T20:20:50.52Z", - "fareName": { - "defaultValue": { - "language": "en-US", - "value": "Fare name" - } - } - } -}) - -def indent(s, spaces): - return s.replace("\n", "\n" + (" " * spaces)) - -def format_payload_dotnet(payload, _): - output = [] - payload = (payload - .replace(' "', " ") - .replace('": ', " = ") - .replace(" string = ", ' @string = ') - .replace("]", "}")) - for line in payload.split("\n"): - _indent = len(line) - len(line.lstrip(" ")) - if line.endswith("{"): - line = line[:-1] + "new\n%s{" % (" " * _indent) - if line.endswith("["): - line = line[:-1] + "new object[]\n%s{" % (" " * _indent) - output.append(line) - return "\n".join(output) - -def format_payload_go(payload, name): - payload = ("\n" + payload.replace(" ", "\t") + "\n").replace("\n", "\n\t").replace(", \n", ",\n") - if name == "$batch_object_payload": - payload = payload.replace("\n", "\n\t") - return payload - -lang_config = { - "go": { - "ext": "go", - "class_id": '"%s.%s"', - "object_id": '"%s.%s"', - "filename": lambda s: "demo_%s.go" % s.lower(), - "formatter": format_payload_go, - }, - "java": { - "ext": "java", - "class_id": "%s.%s", - "object_id": "%s", - "formatter": lambda s, _: '\n "' + s.replace('"', '\\"').replace("\n", '"\n + "') + '"', - "filename": lambda s: "src/main/java/Demo%s.java" % s.title(), - }, - "python": { - "ext": "py", - "class_id": '"%s.%s" % (issuer_id, class_id)', - "object_id": "object_id", - "filename": lambda s: "demo_%s.py" % s.lower(), - }, - "nodejs": { - "ext": "js", - "class_id": "`${issuerId}.${classId}`", - "object_id": "objectId", - "formatter": lambda s, _: indent(s, 2), - "filename": lambda s: "demo-%s.js" % s.lower(), - }, - "php": { - "ext": "php", - "class_id": '"{$issuerId}.{$classId}"', - "object_id": '"{$objectId}"', - "filename": lambda s: "demo_%s.php" % s.lower(), - }, - "dotnet": { - "ext": "cs", - "class_id": '$"{issuerId}.{classId}"', - "object_id": "objectId", - "formatter": format_payload_dotnet, - "filename": lambda s: "Demo%s.cs.example" % s.title(), - "indent": 4, - }, -} - -path = lambda *s: os.path.join(os.path.dirname(os.path.abspath(__file__)), *s) - -for lang, config in lang_config.items(): - try: - with open(path("template.%s" % config["ext"]), "r") as f: - template = f.read() - except IOError: - continue - for object_type, content in payloads.items(): - output = template - - # JSON payloads - if "$batch_object_payload" not in content: - content["$batch_object_payload"] = content["$object_payload"] - for name, value in content.items(): - payload = json.dumps(value, indent=config.get("indent", 2)) - if "formatter" in config: - payload = config["formatter"](payload, name) - output = output.replace(name, payload) - - # code placeholders - config["object_type"] = object_type - config["object_type_lowercase"] = object_type.lower() - config["object_type_titlecase"] = object_type.title() - for name in ("object_type_titlecase", "object_type_lowercase", "object_type", "class_id", "object_id"): - output = output.replace('"$%s"' % name, config[name]) - output = output.replace('$%s' % name, config[name]) - - with open(path("..", lang, config["filename"](object_type)), "w") as f: - f.write(output) \ No newline at end of file diff --git a/templates/template.go b/templates/template.go deleted file mode 100644 index 64dd7d9..0000000 --- a/templates/template.go +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2023 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// [START setup] -// [START imports] -package main - -import ( - "bytes" - "encoding/json" - "fmt" - "github.com/golang-jwt/jwt" - "github.com/google/uuid" - "golang.org/x/oauth2" - "golang.org/x/oauth2/google" - oauthJwt "golang.org/x/oauth2/jwt" - "io" - "net/http" - "os" - "strings" -) - -// [END imports] - -const ( - batchUrl = "https://walletobjects.googleapis.com/batch" - classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/$object_typeClass" - objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/$object_typeObject" -) - -// [END setup] - -type demo$object_type_titlecase struct { - credentials *oauthJwt.Config - httpClient *http.Client - batchUrl, classUrl, objectUrl string -} - -// [START auth] -// Create authenticated HTTP client using a service account file. -func (d *demo$object_type_titlecase) auth() { - b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")) - credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer") - d.credentials = credentials - d.httpClient = d.credentials.Client(oauth2.NoContext) -} - -// [END auth] - -// [START createClass] -// Create a class. -func (d *demo$object_type_titlecase) createClass(issuerId, classSuffix string) { - newClass := fmt.Sprintf(`$class_payload`, issuerId, classSuffix) - - res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass))) - - if err != nil { - fmt.Println(err) - } else { - b, _ := io.ReadAll(res.Body) - fmt.Printf("Class insert response:\n%s\n", b) - } -} - -// [END createClass] - -// [START createObject] -// Create an object. -func (d *demo$object_type_titlecase) createObject(issuerId, classSuffix, objectSuffix string) { - newObject := fmt.Sprintf(`$object_payload`, issuerId, classSuffix, issuerId, objectSuffix) - - res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject))) - - if err != nil { - fmt.Println(err) - } else { - b, _ := io.ReadAll(res.Body) - fmt.Printf("Object insert response:\n%s\n", b) - } -} - -// [END createObject] - -// [START expireObject] -// Expire an object. -// -// Sets the object's state to Expired. If the valid time interval is -// already set, the pass will expire automatically up to 24 hours after. -func (d *demo$object_type_titlecase) expireObject(issuerId, objectSuffix string) { - patchBody := `{"state": "EXPIRED"}` - url := fmt.Sprintf("%s/%s.%s", objectUrl, issuerId, objectSuffix) - req, _ := http.NewRequest(http.MethodPatch, url, bytes.NewBuffer([]byte(patchBody))) - res, err := d.httpClient.Do(req) - - if err != nil { - fmt.Println(err) - } else { - b, _ := io.ReadAll(res.Body) - fmt.Printf("Object expiration response:\n%s\n", b) - } -} - -// [END expireObject] - -// [START jwtNew] -// Generate a signed JWT that creates a new pass class and object. -// -// When the user opens the "Add to Google Wallet" URL and saves the pass to -// their wallet, the pass class and object defined in the JWT are -// created. This allows you to create multiple pass classes and objects in -// one API call when the user saves the pass to their wallet. -func (d *demo$object_type_titlecase) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) { - newClass := fmt.Sprintf(`$class_payload`, issuerId, classSuffix) - - newObject := fmt.Sprintf(`$object_payload`, issuerId, classSuffix, issuerId, objectSuffix) - - var payload map[string]interface{} - json.Unmarshal([]byte(fmt.Sprintf(` - { - "genericClasses": [%s], - "genericObjects": [%s] - } - `, newClass, newObject)), &payload) - - claims := jwt.MapClaims{ - "iss": d.credentials.Email, - "aud": "google", - "origins": []string{"www.example.com"}, - "typ": "savetowallet", - "payload": payload, - } - - // The service account credentials are used to sign the JWT - key, _ := jwt.ParseRSAPrivateKeyFromPEM(d.credentials.PrivateKey) - token, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key) - - fmt.Println("Add to Google Wallet link") - fmt.Println("https://pay.google.com/gp/v/save/" + token) -} - -// [END jwtNew] - -// [START jwtExisting] -// Generate a signed JWT that references an existing pass object. - -// When the user opens the "Add to Google Wallet" URL and saves the pass to -// their wallet, the pass objects defined in the JWT are added to the -// user's Google Wallet app. This allows the user to save multiple pass -// objects in one API call. -func (d *demo$object_type_titlecase) createJwtExistingObjects(issuerId string) { - var payload map[string]interface{} - json.Unmarshal([]byte(fmt.Sprintf(` - { - "eventTicketObjects": [{ - "id": "%s.EVENT_OBJECT_SUFFIX", - "classId": "%s.EVENT_CLASS_SUFFIX" - }], - - "flightObjects": [{ - "id": "%s.FLIGHT_OBJECT_SUFFIX", - "classId": "%s.FLIGHT_CLASS_SUFFIX" - }], - - "genericObjects": [{ - "id": "%s.GENERIC_OBJECT_SUFFIX", - "classId": "%s.GENERIC_CLASS_SUFFIX" - }], - - "giftCardObjects": [{ - "id": "%s.GIFT_CARD_OBJECT_SUFFIX", - "classId": "%s.GIFT_CARD_CLASS_SUFFIX" - }], - - "loyaltyObjects": [{ - "id": "%s.LOYALTY_OBJECT_SUFFIX", - "classId": "%s.LOYALTY_CLASS_SUFFIX" - }], - - "offerObjects": [{ - "id": "%s.OFFER_OBJECT_SUFFIX", - "classId": "%s.OFFER_CLASS_SUFFIX" - }], - - "transitObjects": [{ - "id": "%s.TRANSIT_OBJECT_SUFFIX", - "classId": "%s.TRANSIT_CLASS_SUFFIX" - }] - } - `, issuerId)), &payload) - - claims := jwt.MapClaims{ - "iss": d.credentials.Email, - "aud": "google", - "origins": []string{"www.example.com"}, - "typ": "savetowallet", - "payload": payload, - } - - // The service account credentials are used to sign the JWT - key, _ := jwt.ParseRSAPrivateKeyFromPEM(d.credentials.PrivateKey) - token, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key) - - fmt.Println("Add to Google Wallet link") - fmt.Println("https://pay.google.com/gp/v/save/" + token) -} - -// [END jwtExisting] - -// [START batch] -// Batch create Google Wallet objects from an existing class. -func (d *demo$object_type_titlecase) batchCreateObjects(issuerId, classSuffix string) { - data := "" - for i := 0; i < 3; i++ { - objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_") - - batchObject := fmt.Sprintf(`$batch_object_payload`, issuerId, classSuffix, issuerId, objectSuffix) - - data += "--batch_createobjectbatch\n" - data += "Content-Type: application/json\n\n" - data += "POST /walletobjects/v1/$object_typeObject\n\n" - data += batchObject + "\n\n" - } - data += "--batch_createobjectbatch--" - - res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data))) - - if err != nil { - fmt.Println(err) - } else { - b, _ := io.ReadAll(res.Body) - fmt.Printf("Batch insert response:\n%s\n", b) - } -} - -// [END batch] - -func main() { - if len(os.Args) == 0 { - fmt.Println("Usage: go run demo_$object_type_lowercase.go ") - os.Exit(1) - } - - issuerId := os.Getenv("WALLET_ISSUER_ID") - classSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_") - objectSuffix := fmt.Sprintf("%s-%s", strings.ReplaceAll(uuid.New().String(), "-", "_"), classSuffix) - - d := demo$object_type_titlecase{} - - d.auth() - d.createClass(issuerId, classSuffix) - d.createObject(issuerId, classSuffix, objectSuffix) - d.expireObject(issuerId, objectSuffix) - d.createJwtNewObjects(issuerId, classSuffix, objectSuffix) - d.createJwtExistingObjects(issuerId) - d.batchCreateObjects(issuerId, classSuffix) -}