mirror of
https://github.com/google-wallet/rest-samples.git
synced 2026-01-09 05:28:11 -05:00
Use installable Google APIs lib for Go
This commit is contained in:
@@ -20,6 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -27,35 +28,34 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass"
|
||||
objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoEventticket struct {
|
||||
credentials *oauthJwt.Config
|
||||
httpClient *http.Client
|
||||
batchUrl, classUrl, objectUrl string
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
// Create authenticated HTTP client using a service account file.
|
||||
func (d *demoEventticket) auth() {
|
||||
b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
|
||||
credentialsFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.httpClient = d.credentials.Client(oauth2.NoContext)
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
}
|
||||
|
||||
// [END auth]
|
||||
@@ -63,28 +63,21 @@ func (d *demoEventticket) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoEventticket) createClass(issuerId, classSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"eventId": "EVENT_ID",
|
||||
"eventName": {
|
||||
"defaultValue": {
|
||||
"value": "Event name",
|
||||
"language": "en-US"
|
||||
}
|
||||
eventticketClass := new(walletobjects.EventTicketClass)
|
||||
eventticketClass.Id = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
eventticketClass.EventName = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Event name",
|
||||
},
|
||||
"issuerName": "Issuer name",
|
||||
"id": "%s.%s",
|
||||
"reviewStatus": "UNDER_REVIEW"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass)))
|
||||
|
||||
eventticketClass.IssuerName = "Issuer name"
|
||||
eventticketClass.ReviewStatus = "UNDER_REVIEW"
|
||||
res, err := d.service.Eventticketclass.Insert(eventticketClass).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert class: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Class insert response:\n%s\n", b)
|
||||
fmt.Printf("Class insert id:\n%v\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,107 +86,90 @@ func (d *demoEventticket) createClass(issuerId, classSuffix string) {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoEventticket) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"ticketHolderName": "Ticket holder name",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
eventticketObject := new(walletobjects.EventTicketObject)
|
||||
eventticketObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
eventticketObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
eventticketObject.TicketHolderName = "Ticket holder name"
|
||||
eventticketObject.TicketNumber = "Ticket number"
|
||||
eventticketObject.State = "ACTIVE"
|
||||
eventticketObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
eventticketObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
eventticketObject.Locations = []*walletobjects.LatLongPoint{
|
||||
&walletobjects.LatLongPoint{
|
||||
Latitude: 37.424015499999996,
|
||||
Longitude: -122.09259560000001,
|
||||
},
|
||||
}
|
||||
eventticketObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
eventticketObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
eventticketObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
}
|
||||
eventticketObject.SeatInfo = &walletobjects.EventSeat{
|
||||
Gate: &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "A",
|
||||
},
|
||||
},
|
||||
Section: &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "5",
|
||||
},
|
||||
},
|
||||
Row: &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "G3",
|
||||
},
|
||||
},
|
||||
Seat: &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "42",
|
||||
},
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ticketNumber": "Ticket number",
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"seatInfo": {
|
||||
"gate": {
|
||||
"defaultValue": {
|
||||
"value": "A",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"defaultValue": {
|
||||
"value": "5",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"row": {
|
||||
"defaultValue": {
|
||||
"value": "G3",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"seat": {
|
||||
"defaultValue": {
|
||||
"value": "42",
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))
|
||||
|
||||
res, err := d.service.Eventticketobject.Insert(eventticketObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object insert response:\n%s\n", b)
|
||||
fmt.Printf("Object insert id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,16 +181,14 @@ func (d *demoEventticket) createObject(issuerId, classSuffix, objectSuffix strin
|
||||
// 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 *demoEventticket) 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)
|
||||
|
||||
eventticketObject := &walletobjects.EventTicketObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Eventticketobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), eventticketObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to patch object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object expiration response:\n%s\n", b)
|
||||
fmt.Printf("Object expiration id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,123 +202,20 @@ func (d *demoEventticket) expireObject(issuerId, objectSuffix string) {
|
||||
// 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 *demoEventticket) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"eventId": "EVENT_ID",
|
||||
"eventName": {
|
||||
"defaultValue": {
|
||||
"value": "Event name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"issuerName": "Issuer name",
|
||||
"id": "%s.%s",
|
||||
"reviewStatus": "UNDER_REVIEW"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
eventticketObject := new(walletobjects.EventTicketObject)
|
||||
eventticketObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
eventticketObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
eventticketObject.TicketHolderName = "Ticket holder name"
|
||||
eventticketObject.TicketNumber = "Ticket number"
|
||||
eventticketObject.State = "ACTIVE"
|
||||
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"ticketHolderName": "Ticket holder name",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ticketNumber": "Ticket number",
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"seatInfo": {
|
||||
"gate": {
|
||||
"defaultValue": {
|
||||
"value": "A",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"defaultValue": {
|
||||
"value": "5",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"row": {
|
||||
"defaultValue": {
|
||||
"value": "G3",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"seat": {
|
||||
"defaultValue": {
|
||||
"value": "42",
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
var payload map[string]interface{}
|
||||
eventticketJson, _ := json.Marshal(eventticketObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"genericClasses": [%s],
|
||||
"genericObjects": [%s]
|
||||
"eventticketObjects": [%s]
|
||||
}
|
||||
`, newClass, newObject)), &payload)
|
||||
|
||||
`, eventticketJson)), &payload)
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -370,7 +241,7 @@ func (d *demoEventticket) createJwtNewObjects(issuerId, classSuffix, objectSuffi
|
||||
// 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 *demoEventticket) createJwtExistingObjects(issuerId string) {
|
||||
func (d *demoEventticket) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
@@ -394,7 +265,7 @@ func (d *demoEventticket) createJwtExistingObjects(issuerId string) {
|
||||
"classId": "%s.GIFT_CARD_CLASS_SUFFIX"
|
||||
}],
|
||||
|
||||
"loyaltyObjects": [{
|
||||
"eventticketObjects": [{
|
||||
"id": "%s.LOYALTY_OBJECT_SUFFIX",
|
||||
"classId": "%s.LOYALTY_CLASS_SUFFIX"
|
||||
}],
|
||||
@@ -436,99 +307,15 @@ func (d *demoEventticket) batchCreateObjects(issuerId, classSuffix string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
|
||||
batchObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"ticketHolderName": "Ticket holder name",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ticketNumber": "Ticket number",
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"seatInfo": {
|
||||
"gate": {
|
||||
"defaultValue": {
|
||||
"value": "A",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"defaultValue": {
|
||||
"value": "5",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"row": {
|
||||
"defaultValue": {
|
||||
"value": "G3",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"seat": {
|
||||
"defaultValue": {
|
||||
"value": "42",
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
eventticketObject := new(walletobjects.EventTicketObject)
|
||||
eventticketObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
eventticketObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
eventticketObject.TicketHolderName = "Ticket holder name"
|
||||
eventticketObject.TicketNumber = "Ticket number"
|
||||
eventticketObject.State = "ACTIVE"
|
||||
|
||||
eventticketJson, _ := json.Marshal(eventticketObject)
|
||||
batchObject := fmt.Sprintf("%s", eventticketJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
data += "Content-Type: application/json\n\n"
|
||||
@@ -537,9 +324,7 @@ func (d *demoEventticket) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
|
||||
// batchUrl = 'https://walletobjects.googleapis.com/batch';
|
||||
res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -552,11 +337,6 @@ func (d *demoEventticket) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_eventticket.go <issuer-id>")
|
||||
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)
|
||||
@@ -568,6 +348,6 @@ func main() {
|
||||
d.createObject(issuerId, classSuffix, objectSuffix)
|
||||
d.expireObject(issuerId, objectSuffix)
|
||||
d.createJwtNewObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.createJwtExistingObjects(issuerId)
|
||||
d.createJwtExistingObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.batchCreateObjects(issuerId, classSuffix)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -27,35 +28,34 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/flightClass"
|
||||
objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/flightObject"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoFlight struct {
|
||||
credentials *oauthJwt.Config
|
||||
httpClient *http.Client
|
||||
batchUrl, classUrl, objectUrl string
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
// Create authenticated HTTP client using a service account file.
|
||||
func (d *demoFlight) auth() {
|
||||
b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
|
||||
credentialsFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.httpClient = d.credentials.Client(oauth2.NoContext)
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
}
|
||||
|
||||
// [END auth]
|
||||
@@ -63,38 +63,33 @@ func (d *demoFlight) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoFlight) createClass(issuerId, classSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"origin": {
|
||||
"terminal": "1",
|
||||
"gate": "A2",
|
||||
"airportIataCode": "LAX"
|
||||
},
|
||||
"flightHeader": {
|
||||
"carrier": {
|
||||
"carrierIataCode": "LX"
|
||||
},
|
||||
"flightNumber": "123"
|
||||
},
|
||||
"localScheduledDepartureDateTime": "2023-07-02T15:30:00",
|
||||
"reviewStatus": "UNDER_REVIEW",
|
||||
"issuerName": "Issuer name",
|
||||
"destination": {
|
||||
"terminal": "2",
|
||||
"gate": "C3",
|
||||
"airportIataCode": "SFO"
|
||||
},
|
||||
"id": "%s.%s"
|
||||
flightClass := new(walletobjects.FlightClass)
|
||||
flightClass.Id = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
flightClass.ReviewStatus = "UNDER_REVIEW"
|
||||
flightClass.IssuerName = "Issuer name"
|
||||
flightClass.Origin = &walletobjects.AirportInfo{
|
||||
Terminal: "1",
|
||||
Gate: "A2",
|
||||
AirportIataCode: "LAX",
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass)))
|
||||
flightClass.Destination = &walletobjects.AirportInfo{
|
||||
Terminal: "2",
|
||||
Gate: "C3",
|
||||
AirportIataCode: "SFO",
|
||||
}
|
||||
flightClass.FlightHeader = &walletobjects.FlightHeader{
|
||||
Carrier: &walletobjects.FlightCarrier{
|
||||
CarrierIataCode: "LX",
|
||||
},
|
||||
FlightNumber: "123",
|
||||
}
|
||||
flightClass.LocalScheduledDepartureDateTime = "2023-06-12T23:20:50"
|
||||
|
||||
res, err := d.service.Flightclass.Insert(flightClass).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert class: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Class insert response:\n%s\n", b)
|
||||
fmt.Printf("Class insert id:\n%v\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,87 +98,70 @@ func (d *demoFlight) createClass(issuerId, classSuffix string) {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoFlight) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"passengerName": "Passenger name",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"boardingAndSeatingInfo": {
|
||||
"boardingGroup": "B",
|
||||
"seatNumber": "42"
|
||||
},
|
||||
"reservationInfo": {
|
||||
"confirmationCode": "Confirmation code"
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"id": "%s.%s"
|
||||
flightObject := new(walletobjects.FlightObject)
|
||||
flightObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
flightObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
flightObject.State = "ACTIVE"
|
||||
flightObject.PassengerName = "Passenger name"
|
||||
flightObject.ReservationInfo = &walletobjects.ReservationInfo{
|
||||
ConfirmationCode: "Confirmation code",
|
||||
}
|
||||
flightObject.BoardingAndSeatingInfo = &walletobjects.BoardingAndSeatingInfo{
|
||||
BoardingGroup: "B",
|
||||
SeatNumber: "42",
|
||||
}
|
||||
flightObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
flightObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
flightObject.Locations = []*walletobjects.LatLongPoint{
|
||||
&walletobjects.LatLongPoint{
|
||||
Latitude: 37.424015499999996,
|
||||
Longitude: -122.09259560000001,
|
||||
},
|
||||
}
|
||||
flightObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
flightObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
flightObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))
|
||||
|
||||
res, err := d.service.Flightobject.Insert(flightObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object insert response:\n%s\n", b)
|
||||
fmt.Printf("Object insert id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,16 +173,14 @@ func (d *demoFlight) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
// 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 *demoFlight) 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)
|
||||
|
||||
flightObject := &walletobjects.FlightObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Flightobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), flightObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to patch object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object expiration response:\n%s\n", b)
|
||||
fmt.Printf("Object expiration id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,113 +194,22 @@ func (d *demoFlight) expireObject(issuerId, objectSuffix string) {
|
||||
// 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 *demoFlight) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"origin": {
|
||||
"terminal": "1",
|
||||
"gate": "A2",
|
||||
"airportIataCode": "LAX"
|
||||
},
|
||||
"flightHeader": {
|
||||
"carrier": {
|
||||
"carrierIataCode": "LX"
|
||||
},
|
||||
"flightNumber": "123"
|
||||
},
|
||||
"localScheduledDepartureDateTime": "2023-07-02T15:30:00",
|
||||
"reviewStatus": "UNDER_REVIEW",
|
||||
"issuerName": "Issuer name",
|
||||
"destination": {
|
||||
"terminal": "2",
|
||||
"gate": "C3",
|
||||
"airportIataCode": "SFO"
|
||||
},
|
||||
"id": "%s.%s"
|
||||
flightObject := new(walletobjects.FlightObject)
|
||||
flightObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
flightObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
flightObject.State = "ACTIVE"
|
||||
flightObject.PassengerName = "Passenger name"
|
||||
flightObject.ReservationInfo = &walletobjects.ReservationInfo{
|
||||
ConfirmationCode: "Confirmation code",
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"passengerName": "Passenger name",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"boardingAndSeatingInfo": {
|
||||
"boardingGroup": "B",
|
||||
"seatNumber": "42"
|
||||
},
|
||||
"reservationInfo": {
|
||||
"confirmationCode": "Confirmation code"
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
var payload map[string]interface{}
|
||||
flightJson, _ := json.Marshal(flightObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"genericClasses": [%s],
|
||||
"genericObjects": [%s]
|
||||
"flightObjects": [%s]
|
||||
}
|
||||
`, newClass, newObject)), &payload)
|
||||
|
||||
`, flightJson)), &payload)
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -350,7 +235,7 @@ func (d *demoFlight) createJwtNewObjects(issuerId, classSuffix, objectSuffix str
|
||||
// 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 *demoFlight) createJwtExistingObjects(issuerId string) {
|
||||
func (d *demoFlight) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
@@ -379,7 +264,7 @@ func (d *demoFlight) createJwtExistingObjects(issuerId string) {
|
||||
"classId": "%s.LOYALTY_CLASS_SUFFIX"
|
||||
}],
|
||||
|
||||
"offerObjects": [{
|
||||
"flightObjects": [{
|
||||
"id": "%s.OFFER_OBJECT_SUFFIX",
|
||||
"classId": "%s.OFFER_CLASS_SUFFIX"
|
||||
}],
|
||||
@@ -416,79 +301,17 @@ func (d *demoFlight) batchCreateObjects(issuerId, classSuffix string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
|
||||
batchObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"passengerName": "Passenger name",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"boardingAndSeatingInfo": {
|
||||
"boardingGroup": "B",
|
||||
"seatNumber": "42"
|
||||
},
|
||||
"reservationInfo": {
|
||||
"confirmationCode": "Confirmation code"
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"id": "%s.%s"
|
||||
flightObject := new(walletobjects.FlightObject)
|
||||
flightObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
flightObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
flightObject.State = "ACTIVE"
|
||||
flightObject.PassengerName = "Passenger name"
|
||||
flightObject.ReservationInfo = &walletobjects.ReservationInfo{
|
||||
ConfirmationCode: "Confirmation code",
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
flightJson, _ := json.Marshal(flightObject)
|
||||
batchObject := fmt.Sprintf("%s", flightJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
data += "Content-Type: application/json\n\n"
|
||||
@@ -497,8 +320,7 @@ func (d *demoFlight) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
// batchUrl = 'https://walletobjects.googleapis.com/batch';
|
||||
res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -511,11 +333,6 @@ func (d *demoFlight) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_flight.go <issuer-id>")
|
||||
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)
|
||||
@@ -527,6 +344,6 @@ func main() {
|
||||
d.createObject(issuerId, classSuffix, objectSuffix)
|
||||
d.expireObject(issuerId, objectSuffix)
|
||||
d.createJwtNewObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.createJwtExistingObjects(issuerId)
|
||||
d.createJwtExistingObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.batchCreateObjects(issuerId, classSuffix)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -27,35 +28,34 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/genericClass"
|
||||
objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/genericObject"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoGeneric struct {
|
||||
credentials *oauthJwt.Config
|
||||
httpClient *http.Client
|
||||
batchUrl, classUrl, objectUrl string
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
// Create authenticated HTTP client using a service account file.
|
||||
func (d *demoGeneric) auth() {
|
||||
b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
|
||||
credentialsFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.httpClient = d.credentials.Client(oauth2.NoContext)
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
}
|
||||
|
||||
// [END auth]
|
||||
@@ -63,19 +63,13 @@ func (d *demoGeneric) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoGeneric) createClass(issuerId, classSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass)))
|
||||
|
||||
genericClass := new(walletobjects.GenericClass)
|
||||
genericClass.Id = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
res, err := d.service.Genericclass.Insert(genericClass).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert class: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Class insert response:\n%s\n", b)
|
||||
fmt.Printf("Class insert id:\n%v\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,97 +78,68 @@ func (d *demoGeneric) createClass(issuerId, classSuffix string) {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoGeneric) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"cardTitle": {
|
||||
"defaultValue": {
|
||||
"value": "Generic card title",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"header": {
|
||||
"defaultValue": {
|
||||
"value": "Generic header",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"logo": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Generic card logo",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
|
||||
}
|
||||
},
|
||||
"hexBackgroundColor": "#4285f4",
|
||||
"id": "%s.%s"
|
||||
genericObject := new(walletobjects.GenericObject)
|
||||
genericObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
genericObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
genericObject.State = "ACTIVE"
|
||||
genericObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
genericObject.CardTitle = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Card title",
|
||||
},
|
||||
}
|
||||
genericObject.Header = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Header",
|
||||
},
|
||||
}
|
||||
genericObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
genericObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
genericObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
genericObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))
|
||||
|
||||
res, err := d.service.Genericobject.Insert(genericObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object insert response:\n%s\n", b)
|
||||
fmt.Printf("Object insert id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,16 +151,14 @@ func (d *demoGeneric) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
// 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 *demoGeneric) 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)
|
||||
|
||||
genericObject := &walletobjects.GenericObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Genericobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), genericObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to patch object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object expiration response:\n%s\n", b)
|
||||
fmt.Printf("Object expiration id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,104 +172,34 @@ func (d *demoGeneric) expireObject(issuerId, objectSuffix string) {
|
||||
// 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 *demoGeneric) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"id": "%s.%s"
|
||||
genericObject := new(walletobjects.GenericObject)
|
||||
genericObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
genericObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
genericObject.State = "ACTIVE"
|
||||
genericObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"cardTitle": {
|
||||
"defaultValue": {
|
||||
"value": "Generic card title",
|
||||
"language": "en-US"
|
||||
}
|
||||
genericObject.CardTitle = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Card title",
|
||||
},
|
||||
}
|
||||
genericObject.Header = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Header",
|
||||
},
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"header": {
|
||||
"defaultValue": {
|
||||
"value": "Generic header",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"logo": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Generic card logo",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
|
||||
}
|
||||
},
|
||||
"hexBackgroundColor": "#4285f4",
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
var payload map[string]interface{}
|
||||
genericJson, _ := json.Marshal(genericObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"genericClasses": [%s],
|
||||
"genericObjects": [%s]
|
||||
}
|
||||
`, newClass, newObject)), &payload)
|
||||
|
||||
`, genericJson)), &payload)
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -332,7 +225,7 @@ func (d *demoGeneric) createJwtNewObjects(issuerId, classSuffix, objectSuffix st
|
||||
// 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 *demoGeneric) createJwtExistingObjects(issuerId string) {
|
||||
func (d *demoGeneric) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
@@ -398,89 +291,29 @@ func (d *demoGeneric) batchCreateObjects(issuerId, classSuffix string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
|
||||
batchObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"cardTitle": {
|
||||
"defaultValue": {
|
||||
"value": "Generic card title",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"header": {
|
||||
"defaultValue": {
|
||||
"value": "Generic header",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"logo": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Generic card logo",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg"
|
||||
}
|
||||
},
|
||||
"hexBackgroundColor": "#4285f4",
|
||||
"id": "%s.%s"
|
||||
genericObject := new(walletobjects.GenericObject)
|
||||
genericObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
genericObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
genericObject.State = "ACTIVE"
|
||||
genericObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
genericObject.CardTitle = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Card title",
|
||||
},
|
||||
}
|
||||
genericObject.Header = &walletobjects.LocalizedString{
|
||||
DefaultValue: &walletobjects.TranslatedString{
|
||||
Language: "en-us",
|
||||
Value: "Header",
|
||||
},
|
||||
}
|
||||
|
||||
genericJson, _ := json.Marshal(genericObject)
|
||||
batchObject := fmt.Sprintf("%s", genericJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
data += "Content-Type: application/json\n\n"
|
||||
@@ -489,8 +322,7 @@ func (d *demoGeneric) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
// batchUrl = 'https://walletobjects.googleapis.com/batch';
|
||||
res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -503,11 +335,6 @@ func (d *demoGeneric) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_generic.go <issuer-id>")
|
||||
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)
|
||||
@@ -519,6 +346,6 @@ func main() {
|
||||
d.createObject(issuerId, classSuffix, objectSuffix)
|
||||
d.expireObject(issuerId, objectSuffix)
|
||||
d.createJwtNewObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.createJwtExistingObjects(issuerId)
|
||||
d.createJwtExistingObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.batchCreateObjects(issuerId, classSuffix)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -27,35 +28,34 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/giftCardClass"
|
||||
objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/giftCardObject"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoGiftcard struct {
|
||||
credentials *oauthJwt.Config
|
||||
httpClient *http.Client
|
||||
batchUrl, classUrl, objectUrl string
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
// Create authenticated HTTP client using a service account file.
|
||||
func (d *demoGiftcard) auth() {
|
||||
b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
|
||||
credentialsFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.httpClient = d.credentials.Client(oauth2.NoContext)
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
}
|
||||
|
||||
// [END auth]
|
||||
@@ -63,21 +63,15 @@ func (d *demoGiftcard) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoGiftcard) createClass(issuerId, classSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"issuerName": "Issuer name",
|
||||
"id": "%s.%s",
|
||||
"reviewStatus": "UNDER_REVIEW"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass)))
|
||||
|
||||
giftcardClass := new(walletobjects.GiftCardClass)
|
||||
giftcardClass.Id = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
giftcardClass.IssuerName = "Issuer name"
|
||||
giftcardClass.ReviewStatus = "UNDER_REVIEW"
|
||||
res, err := d.service.Giftcardclass.Insert(giftcardClass).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert class: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Class insert response:\n%s\n", b)
|
||||
fmt.Printf("Class insert id:\n%v\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,88 +80,71 @@ func (d *demoGiftcard) createClass(issuerId, classSuffix string) {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoGiftcard) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"pin": "1234",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"balanceUpdateTime": {
|
||||
"date": "2020-04-12T16:20:50.52-04:00"
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"cardNumber": "Card number",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"balance": {
|
||||
"micros": 20000000,
|
||||
"currencyCode": "USD"
|
||||
},
|
||||
"id": "%s.%s"
|
||||
giftcardObject := new(walletobjects.GiftCardObject)
|
||||
giftcardObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
giftcardObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
giftcardObject.State = "ACTIVE"
|
||||
giftcardObject.CardNumber = "Card number"
|
||||
giftcardObject.Pin = "1234"
|
||||
giftcardObject.Balance = &walletobjects.Money{
|
||||
Micros: 20000000,
|
||||
CurrencyCode: "USD",
|
||||
}
|
||||
giftcardObject.BalanceUpdateTime = &walletobjects.DateTime{
|
||||
Date: "2023-12-12T23:20:50.52Z",
|
||||
}
|
||||
giftcardObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
giftcardObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
giftcardObject.Locations = []*walletobjects.LatLongPoint{
|
||||
&walletobjects.LatLongPoint{
|
||||
Latitude: 37.424015499999996,
|
||||
Longitude: -122.09259560000001,
|
||||
},
|
||||
}
|
||||
giftcardObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
giftcardObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
giftcardObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))
|
||||
|
||||
res, err := d.service.Giftcardobject.Insert(giftcardObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object insert response:\n%s\n", b)
|
||||
fmt.Printf("Object insert id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,16 +156,14 @@ func (d *demoGiftcard) createObject(issuerId, classSuffix, objectSuffix string)
|
||||
// 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 *demoGiftcard) 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)
|
||||
|
||||
giftcardObject := &walletobjects.GiftCardObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Giftcardobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), giftcardObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to patch object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object expiration response:\n%s\n", b)
|
||||
fmt.Printf("Object expiration id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,97 +177,19 @@ func (d *demoGiftcard) expireObject(issuerId, objectSuffix string) {
|
||||
// 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 *demoGiftcard) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"issuerName": "Issuer name",
|
||||
"id": "%s.%s",
|
||||
"reviewStatus": "UNDER_REVIEW"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
giftcardObject := new(walletobjects.GiftCardObject)
|
||||
giftcardObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
giftcardObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
giftcardObject.State = "ACTIVE"
|
||||
giftcardObject.CardNumber = "Card number"
|
||||
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"pin": "1234",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"balanceUpdateTime": {
|
||||
"date": "2020-04-12T16:20:50.52-04:00"
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"cardNumber": "Card number",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"balance": {
|
||||
"micros": 20000000,
|
||||
"currencyCode": "USD"
|
||||
},
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
var payload map[string]interface{}
|
||||
giftcardJson, _ := json.Marshal(giftcardObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"genericClasses": [%s],
|
||||
"genericObjects": [%s]
|
||||
"giftcardObjects": [%s]
|
||||
}
|
||||
`, newClass, newObject)), &payload)
|
||||
|
||||
`, giftcardJson)), &payload)
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -318,7 +215,7 @@ func (d *demoGiftcard) createJwtNewObjects(issuerId, classSuffix, objectSuffix s
|
||||
// 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 *demoGiftcard) createJwtExistingObjects(issuerId string) {
|
||||
func (d *demoGiftcard) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
@@ -347,7 +244,7 @@ func (d *demoGiftcard) createJwtExistingObjects(issuerId string) {
|
||||
"classId": "%s.LOYALTY_CLASS_SUFFIX"
|
||||
}],
|
||||
|
||||
"offerObjects": [{
|
||||
"giftcardObjects": [{
|
||||
"id": "%s.OFFER_OBJECT_SUFFIX",
|
||||
"classId": "%s.OFFER_CLASS_SUFFIX"
|
||||
}],
|
||||
@@ -384,80 +281,14 @@ func (d *demoGiftcard) batchCreateObjects(issuerId, classSuffix string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
|
||||
batchObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"pin": "1234",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"balanceUpdateTime": {
|
||||
"date": "2020-04-12T16:20:50.52-04:00"
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"cardNumber": "Card number",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"balance": {
|
||||
"micros": 20000000,
|
||||
"currencyCode": "USD"
|
||||
},
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
giftcardObject := new(walletobjects.GiftCardObject)
|
||||
giftcardObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
giftcardObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
giftcardObject.State = "ACTIVE"
|
||||
giftcardObject.CardNumber = "Card number"
|
||||
|
||||
giftcardJson, _ := json.Marshal(giftcardObject)
|
||||
batchObject := fmt.Sprintf("%s", giftcardJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
data += "Content-Type: application/json\n\n"
|
||||
@@ -466,8 +297,7 @@ func (d *demoGiftcard) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
// batchUrl = 'https://walletobjects.googleapis.com/batch';
|
||||
res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -480,11 +310,6 @@ func (d *demoGiftcard) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_giftcard.go <issuer-id>")
|
||||
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)
|
||||
@@ -496,6 +321,6 @@ func main() {
|
||||
d.createObject(issuerId, classSuffix, objectSuffix)
|
||||
d.expireObject(issuerId, objectSuffix)
|
||||
d.createJwtNewObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.createJwtExistingObjects(issuerId)
|
||||
d.createJwtExistingObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.batchCreateObjects(issuerId, classSuffix)
|
||||
}
|
||||
|
||||
@@ -20,35 +20,28 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoLoyalty struct {
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
batchUrl string
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
@@ -58,7 +51,8 @@ func (d *demoLoyalty) auth() {
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to create credentials: %v", err)
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
@@ -69,8 +63,8 @@ func (d *demoLoyalty) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoLoyalty) createClass(issuerId, classSuffix string) {
|
||||
logo := walletobjects.Image {
|
||||
SourceUri: &walletobjects.ImageUri {
|
||||
logo := walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg",
|
||||
},
|
||||
}
|
||||
@@ -90,73 +84,66 @@ func (d *demoLoyalty) createClass(issuerId, classSuffix string) {
|
||||
|
||||
// [END createClass]
|
||||
|
||||
// [START setupObject]
|
||||
// Build a full loyaltyObject.
|
||||
func (d *demoLoyalty) setupObject(issuerId, classSuffix, objectSuffix string) *walletobjects.LoyaltyObject {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoLoyalty) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
loyaltyObject := new(walletobjects.LoyaltyObject)
|
||||
loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
loyaltyObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
loyaltyObject.AccountName = "Account name"
|
||||
loyaltyObject.AccountId = "Account id"
|
||||
loyaltyObject.State = "ACTIVE"
|
||||
loyaltyObject.LoyaltyPoints = &walletobjects.LoyaltyPoints {
|
||||
Balance: &walletobjects.LoyaltyPointsBalance { Int: 800 },
|
||||
Label: "Points",
|
||||
loyaltyObject.LoyaltyPoints = &walletobjects.LoyaltyPoints{
|
||||
Balance: &walletobjects.LoyaltyPointsBalance{Int: 800},
|
||||
Label: "Points",
|
||||
}
|
||||
loyaltyObject.HeroImage = &walletobjects.Image {
|
||||
SourceUri: &walletobjects.ImageUri {
|
||||
loyaltyObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
loyaltyObject.Barcode = &walletobjects.Barcode {
|
||||
Type: "QR_CODE",
|
||||
loyaltyObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
loyaltyObject.Locations = []*walletobjects.LatLongPoint {
|
||||
&walletobjects.LatLongPoint {
|
||||
Latitude: 37.424015499999996,
|
||||
loyaltyObject.Locations = []*walletobjects.LatLongPoint{
|
||||
&walletobjects.LatLongPoint{
|
||||
Latitude: 37.424015499999996,
|
||||
Longitude: -122.09259560000001,
|
||||
},
|
||||
}
|
||||
loyaltyObject.LinksModuleData = &walletobjects.LinksModuleData {
|
||||
Uris: []*walletobjects.Uri {
|
||||
&walletobjects.Uri {
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
loyaltyObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri {
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
loyaltyObject.ImageModulesData = []*walletobjects.ImageModuleData {
|
||||
&walletobjects.ImageModuleData {
|
||||
loyaltyObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image {
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
loyaltyObject.TextModulesData = []*walletobjects.TextModuleData {
|
||||
&walletobjects.TextModuleData {
|
||||
Body: "Text module body",
|
||||
loyaltyObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
}
|
||||
return loyaltyObject
|
||||
}
|
||||
// [END setupObject]
|
||||
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoLoyalty) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
loyaltyObject := d.setupObject(issuerId, classSuffix, objectSuffix)
|
||||
res, err := d.service.Loyaltyobject.Insert(loyaltyObject).Do()
|
||||
if err != nil {
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
@@ -173,7 +160,7 @@ func (d *demoLoyalty) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
// 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 *demoLoyalty) expireObject(issuerId, objectSuffix string) {
|
||||
loyaltyObject := &walletobjects.LoyaltyObject {
|
||||
loyaltyObject := &walletobjects.LoyaltyObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Loyaltyobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), loyaltyObject).Do()
|
||||
@@ -195,11 +182,12 @@ func (d *demoLoyalty) expireObject(issuerId, objectSuffix string) {
|
||||
// one API call when the user saves the pass to their wallet.
|
||||
func (d *demoLoyalty) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
loyaltyObject := new(walletobjects.LoyaltyObject)
|
||||
loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix + "_")
|
||||
loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix+"_")
|
||||
loyaltyObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
loyaltyObject.AccountName = "Account name"
|
||||
loyaltyObject.AccountId = "Account id"
|
||||
loyaltyObject.State = "ACTIVE"
|
||||
|
||||
loyaltyJson, _ := json.Marshal(loyaltyObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
@@ -233,16 +221,46 @@ func (d *demoLoyalty) createJwtNewObjects(issuerId, classSuffix, objectSuffix st
|
||||
// user's Google Wallet app. This allows the user to save multiple pass
|
||||
// objects in one API call.
|
||||
func (d *demoLoyalty) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
loyaltyObject := new(walletobjects.LoyaltyObject)
|
||||
loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
loyaltyObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
loyaltyJson, _ := json.Marshal(loyaltyObject)
|
||||
var payload map[string]any
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"loyaltyObjects":[%s]
|
||||
"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"
|
||||
}]
|
||||
}
|
||||
`, loyaltyJson )), &payload)
|
||||
`, issuerId)), &payload)
|
||||
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -255,7 +273,7 @@ func (d *demoLoyalty) createJwtExistingObjects(issuerId string, classSuffix stri
|
||||
key, _ := jwt.ParseRSAPrivateKeyFromPEM(d.credentials.PrivateKey)
|
||||
token, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key)
|
||||
|
||||
fmt.Println("Add to Google Wallet link for existing objects")
|
||||
fmt.Println("Add to Google Wallet link")
|
||||
fmt.Println("https://pay.google.com/gp/v/save/" + token)
|
||||
}
|
||||
|
||||
@@ -267,9 +285,15 @@ func (d *demoLoyalty) batchCreateObjects(issuerId, classSuffix string) {
|
||||
data := ""
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
loyaltyObject := d.setupObject(issuerId, classSuffix, objectSuffix)
|
||||
|
||||
loyaltyObject := new(walletobjects.LoyaltyObject)
|
||||
loyaltyObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
loyaltyObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
loyaltyObject.AccountName = "Account name"
|
||||
loyaltyObject.AccountId = "Account id"
|
||||
loyaltyObject.State = "ACTIVE"
|
||||
|
||||
loyaltyJson, _ := json.Marshal(loyaltyObject)
|
||||
|
||||
batchObject := fmt.Sprintf("%s", loyaltyJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
@@ -279,7 +303,7 @@ func (d *demoLoyalty) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -292,11 +316,6 @@ func (d *demoLoyalty) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_loyalty.go <issuer-id>")
|
||||
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)
|
||||
|
||||
390
go/demo_offer.go
390
go/demo_offer.go
@@ -20,6 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -27,35 +28,34 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/offerClass"
|
||||
objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/offerObject"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoOffer struct {
|
||||
credentials *oauthJwt.Config
|
||||
httpClient *http.Client
|
||||
batchUrl, classUrl, objectUrl string
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
// Create authenticated HTTP client using a service account file.
|
||||
func (d *demoOffer) auth() {
|
||||
b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
|
||||
credentialsFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.httpClient = d.credentials.Client(oauth2.NoContext)
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
}
|
||||
|
||||
// [END auth]
|
||||
@@ -63,24 +63,18 @@ func (d *demoOffer) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoOffer) createClass(issuerId, classSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"redemptionChannel": "ONLINE",
|
||||
"reviewStatus": "UNDER_REVIEW",
|
||||
"title": "Offer title",
|
||||
"issuerName": "Issuer name",
|
||||
"provider": "Provider name",
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass)))
|
||||
|
||||
offerClass := new(walletobjects.OfferClass)
|
||||
offerClass.Id = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
offerClass.RedemptionChannel = "ONLINE"
|
||||
offerClass.ReviewStatus = "UNDER_REVIEW"
|
||||
offerClass.Title = "Offer title"
|
||||
offerClass.IssuerName = "Issuer name"
|
||||
offerClass.Provider = "Provider name"
|
||||
res, err := d.service.Offerclass.Insert(offerClass).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert class: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Class insert response:\n%s\n", b)
|
||||
fmt.Printf("Class insert id:\n%v\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,87 +83,70 @@ func (d *demoOffer) createClass(issuerId, classSuffix string) {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoOffer) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
offerObject := new(walletobjects.OfferObject)
|
||||
offerObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
offerObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
offerObject.State = "ACTIVE"
|
||||
offerObject.ValidTimeInterval = &walletobjects.TimeInterval{
|
||||
Start: &walletobjects.DateTime{
|
||||
Date: "2023-06-12T23:20:50.52Z",
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
End: &walletobjects.DateTime{
|
||||
Date: "2023-12-12T23:20:50.52Z",
|
||||
},
|
||||
}
|
||||
offerObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
offerObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
offerObject.Locations = []*walletobjects.LatLongPoint{
|
||||
&walletobjects.LatLongPoint{
|
||||
Latitude: 37.424015499999996,
|
||||
Longitude: -122.09259560000001,
|
||||
},
|
||||
}
|
||||
offerObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
offerObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
offerObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"validTimeInterval": {
|
||||
"start": {
|
||||
"date": "2023-06-12T23:20:50.52Z"
|
||||
},
|
||||
"end": {
|
||||
"date": "2023-12-12T23:20:50.52Z"
|
||||
}
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))
|
||||
|
||||
res, err := d.service.Offerobject.Insert(offerObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object insert response:\n%s\n", b)
|
||||
fmt.Printf("Object insert id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,16 +158,14 @@ func (d *demoOffer) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
// 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 *demoOffer) 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)
|
||||
|
||||
offerObject := &walletobjects.OfferObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Offerobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), offerObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to patch object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object expiration response:\n%s\n", b)
|
||||
fmt.Printf("Object expiration id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,99 +179,18 @@ func (d *demoOffer) expireObject(issuerId, objectSuffix string) {
|
||||
// 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 *demoOffer) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"redemptionChannel": "ONLINE",
|
||||
"reviewStatus": "UNDER_REVIEW",
|
||||
"title": "Offer title",
|
||||
"issuerName": "Issuer name",
|
||||
"provider": "Provider name",
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
offerObject := new(walletobjects.OfferObject)
|
||||
offerObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
offerObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
offerObject.State = "ACTIVE"
|
||||
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"validTimeInterval": {
|
||||
"start": {
|
||||
"date": "2023-06-12T23:20:50.52Z"
|
||||
},
|
||||
"end": {
|
||||
"date": "2023-12-12T23:20:50.52Z"
|
||||
}
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
var payload map[string]interface{}
|
||||
offerJson, _ := json.Marshal(offerObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"genericClasses": [%s],
|
||||
"genericObjects": [%s]
|
||||
"offerObjects": [%s]
|
||||
}
|
||||
`, newClass, newObject)), &payload)
|
||||
|
||||
`, offerJson)), &payload)
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -322,7 +216,7 @@ func (d *demoOffer) createJwtNewObjects(issuerId, classSuffix, objectSuffix stri
|
||||
// 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 *demoOffer) createJwtExistingObjects(issuerId string) {
|
||||
func (d *demoOffer) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
@@ -388,79 +282,13 @@ func (d *demoOffer) batchCreateObjects(issuerId, classSuffix string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
|
||||
batchObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"validTimeInterval": {
|
||||
"start": {
|
||||
"date": "2023-06-12T23:20:50.52Z"
|
||||
},
|
||||
"end": {
|
||||
"date": "2023-12-12T23:20:50.52Z"
|
||||
}
|
||||
},
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
offerObject := new(walletobjects.OfferObject)
|
||||
offerObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
offerObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
offerObject.State = "ACTIVE"
|
||||
|
||||
offerJson, _ := json.Marshal(offerObject)
|
||||
batchObject := fmt.Sprintf("%s", offerJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
data += "Content-Type: application/json\n\n"
|
||||
@@ -469,8 +297,7 @@ func (d *demoOffer) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
// batchUrl = 'https://walletobjects.googleapis.com/batch';
|
||||
res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -483,11 +310,6 @@ func (d *demoOffer) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_offer.go <issuer-id>")
|
||||
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)
|
||||
@@ -499,6 +321,6 @@ func main() {
|
||||
d.createObject(issuerId, classSuffix, objectSuffix)
|
||||
d.expireObject(issuerId, objectSuffix)
|
||||
d.createJwtNewObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.createJwtExistingObjects(issuerId)
|
||||
d.createJwtExistingObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.batchCreateObjects(issuerId, classSuffix)
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
@@ -27,35 +28,34 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/google"
|
||||
oauthJwt "golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/option"
|
||||
"google.golang.org/api/walletobjects/v1"
|
||||
"io"
|
||||
"net/http"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// [END imports]
|
||||
|
||||
const (
|
||||
batchUrl = "https://walletobjects.googleapis.com/batch"
|
||||
classUrl = "https://walletobjects.googleapis.com/walletobjects/v1/transitClass"
|
||||
objectUrl = "https://walletobjects.googleapis.com/walletobjects/v1/transitObject"
|
||||
)
|
||||
|
||||
// [END setup]
|
||||
|
||||
type demoTransit struct {
|
||||
credentials *oauthJwt.Config
|
||||
httpClient *http.Client
|
||||
batchUrl, classUrl, objectUrl string
|
||||
credentials *oauthJwt.Config
|
||||
service *walletobjects.Service
|
||||
}
|
||||
|
||||
// [START auth]
|
||||
// Create authenticated HTTP client using a service account file.
|
||||
func (d *demoTransit) auth() {
|
||||
b, _ := os.ReadFile(os.Getenv("GOOGLE_APPLICATION_CREDENTIALS"))
|
||||
credentials, _ := google.JWTConfigFromJSON(b, "https://www.googleapis.com/auth/wallet_object.issuer")
|
||||
credentialsFile := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
||||
b, _ := os.ReadFile(credentialsFile)
|
||||
credentials, err := google.JWTConfigFromJSON(b, walletobjects.WalletObjectIssuerScope)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to load credentials: %v", err)
|
||||
}
|
||||
d.credentials = credentials
|
||||
d.httpClient = d.credentials.Client(oauth2.NoContext)
|
||||
d.service, _ = walletobjects.NewService(context.Background(), option.WithCredentialsFile(credentialsFile))
|
||||
}
|
||||
|
||||
// [END auth]
|
||||
@@ -63,33 +63,22 @@ func (d *demoTransit) auth() {
|
||||
// [START createClass]
|
||||
// Create a class.
|
||||
func (d *demoTransit) createClass(issuerId, classSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"logo": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Logo description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png"
|
||||
}
|
||||
logo := walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg",
|
||||
},
|
||||
"issuerName": "Issuer name",
|
||||
"reviewStatus": "UNDER_REVIEW",
|
||||
"id": "%s.%s",
|
||||
"transitType": "BUS"
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(classUrl, "application/json", bytes.NewBuffer([]byte(newClass)))
|
||||
|
||||
transitClass := new(walletobjects.TransitClass)
|
||||
transitClass.Id = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
transitClass.IssuerName = "Issuer name"
|
||||
transitClass.ReviewStatus = "UNDER_REVIEW"
|
||||
transitClass.Logo = &logo
|
||||
transitClass.TransitType = "BUS"
|
||||
res, err := d.service.Transitclass.Insert(transitClass).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert class: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Class insert response:\n%s\n", b)
|
||||
fmt.Printf("Class insert id:\n%v\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,106 +87,68 @@ func (d *demoTransit) createClass(issuerId, classSuffix string) {
|
||||
// [START createObject]
|
||||
// Create an object.
|
||||
func (d *demoTransit) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"passengerNames": "Passenger names",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"ticketLeg": {
|
||||
"destinationStationCode": "SFO",
|
||||
"destinationName": {
|
||||
"defaultValue": {
|
||||
"value": "Destination name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
|
||||
"originStationCode": "LA",
|
||||
"originName": {
|
||||
"defaultValue": {
|
||||
"value": "Origin name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"departureDateTime": "2020-04-12T16:20:50.52Z",
|
||||
"fareName": {
|
||||
"defaultValue": {
|
||||
"value": "Fare name",
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"passengerType": "SINGLE_PASSENGER",
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"tripType": "ONE_WAY",
|
||||
"id": "%s.%s"
|
||||
transitObject := new(walletobjects.TransitObject)
|
||||
transitObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
transitObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
transitObject.State = "ACTIVE"
|
||||
transitObject.PassengerNames = "Passenger names"
|
||||
transitObject.TripType = "ONE_WAY"
|
||||
transitObject.PassengerType = "SINGLE_PASSENGER"
|
||||
transitObject.TicketLeg = &walletobjects.TicketLeg{
|
||||
DestinationStationCode: "SFO",
|
||||
OriginStationCode: "LA",
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
res, err := d.httpClient.Post(objectUrl, "application/json", bytes.NewBuffer([]byte(newObject)))
|
||||
|
||||
transitObject.HeroImage = &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg",
|
||||
},
|
||||
}
|
||||
transitObject.Barcode = &walletobjects.Barcode{
|
||||
Type: "QR_CODE",
|
||||
Value: "QR code",
|
||||
}
|
||||
transitObject.Locations = []*walletobjects.LatLongPoint{
|
||||
&walletobjects.LatLongPoint{
|
||||
Latitude: 37.424015499999996,
|
||||
Longitude: -122.09259560000001,
|
||||
},
|
||||
}
|
||||
transitObject.LinksModuleData = &walletobjects.LinksModuleData{
|
||||
Uris: []*walletobjects.Uri{
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_URI_ID",
|
||||
Uri: "http://maps.google.com/",
|
||||
Description: "Link module URI description",
|
||||
},
|
||||
&walletobjects.Uri{
|
||||
Id: "LINK_MODULE_TEL_ID",
|
||||
Uri: "tel:6505555555",
|
||||
Description: "Link module tel description",
|
||||
},
|
||||
},
|
||||
}
|
||||
transitObject.ImageModulesData = []*walletobjects.ImageModuleData{
|
||||
&walletobjects.ImageModuleData{
|
||||
Id: "IMAGE_MODULE_ID",
|
||||
MainImage: &walletobjects.Image{
|
||||
SourceUri: &walletobjects.ImageUri{
|
||||
Uri: "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
transitObject.TextModulesData = []*walletobjects.TextModuleData{
|
||||
&walletobjects.TextModuleData{
|
||||
Body: "Text module body",
|
||||
Header: "Text module header",
|
||||
Id: "TEXT_MODULE_ID",
|
||||
},
|
||||
}
|
||||
res, err := d.service.Transitobject.Insert(transitObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to insert object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object insert response:\n%s\n", b)
|
||||
fmt.Printf("Object insert id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,16 +160,14 @@ func (d *demoTransit) createObject(issuerId, classSuffix, objectSuffix string) {
|
||||
// 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 *demoTransit) 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)
|
||||
|
||||
transitObject := &walletobjects.TransitObject{
|
||||
State: "EXPIRED",
|
||||
}
|
||||
res, err := d.service.Transitobject.Patch(fmt.Sprintf("%s.%s", issuerId, objectSuffix), transitObject).Do()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
log.Fatalf("Unable to patch object: %v", err)
|
||||
} else {
|
||||
b, _ := io.ReadAll(res.Body)
|
||||
fmt.Printf("Object expiration response:\n%s\n", b)
|
||||
fmt.Printf("Object expiration id:\n%s\n", res.Id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,127 +181,25 @@ func (d *demoTransit) expireObject(issuerId, objectSuffix string) {
|
||||
// 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 *demoTransit) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) {
|
||||
newClass := fmt.Sprintf(`
|
||||
{
|
||||
"logo": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Logo description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png"
|
||||
}
|
||||
},
|
||||
"issuerName": "Issuer name",
|
||||
"reviewStatus": "UNDER_REVIEW",
|
||||
"id": "%s.%s",
|
||||
"transitType": "BUS"
|
||||
transitObject := new(walletobjects.TransitObject)
|
||||
transitObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
transitObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
transitObject.State = "ACTIVE"
|
||||
transitObject.PassengerNames = "Passenger names"
|
||||
transitObject.TripType = "ONE_WAY"
|
||||
transitObject.PassengerType = "SINGLE_PASSENGER"
|
||||
transitObject.TicketLeg = &walletobjects.TicketLeg{
|
||||
DestinationStationCode: "SFO",
|
||||
OriginStationCode: "LA",
|
||||
}
|
||||
`, issuerId, classSuffix)
|
||||
|
||||
newObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"passengerNames": "Passenger names",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"ticketLeg": {
|
||||
"destinationStationCode": "SFO",
|
||||
"destinationName": {
|
||||
"defaultValue": {
|
||||
"value": "Destination name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
|
||||
"originStationCode": "LA",
|
||||
"originName": {
|
||||
"defaultValue": {
|
||||
"value": "Origin name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"departureDateTime": "2020-04-12T16:20:50.52Z",
|
||||
"fareName": {
|
||||
"defaultValue": {
|
||||
"value": "Fare name",
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"passengerType": "SINGLE_PASSENGER",
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"tripType": "ONE_WAY",
|
||||
"id": "%s.%s"
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
var payload map[string]interface{}
|
||||
transitJson, _ := json.Marshal(transitObject)
|
||||
var payload map[string]any
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
"genericClasses": [%s],
|
||||
"genericObjects": [%s]
|
||||
"transitObjects": [%s]
|
||||
}
|
||||
`, newClass, newObject)), &payload)
|
||||
|
||||
`, transitJson)), &payload)
|
||||
claims := jwt.MapClaims{
|
||||
"iss": d.credentials.Email,
|
||||
"aud": "google",
|
||||
@@ -365,7 +212,7 @@ func (d *demoTransit) createJwtNewObjects(issuerId, classSuffix, objectSuffix st
|
||||
key, _ := jwt.ParseRSAPrivateKeyFromPEM(d.credentials.PrivateKey)
|
||||
token, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key)
|
||||
|
||||
fmt.Println("Add to Google Wallet link")
|
||||
fmt.Println("Add to Google Wallet link for new objects")
|
||||
fmt.Println("https://pay.google.com/gp/v/save/" + token)
|
||||
}
|
||||
|
||||
@@ -378,7 +225,7 @@ func (d *demoTransit) createJwtNewObjects(issuerId, classSuffix, objectSuffix st
|
||||
// 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 *demoTransit) createJwtExistingObjects(issuerId string) {
|
||||
func (d *demoTransit) createJwtExistingObjects(issuerId string, classSuffix string, objectSuffix string) {
|
||||
var payload map[string]interface{}
|
||||
json.Unmarshal([]byte(fmt.Sprintf(`
|
||||
{
|
||||
@@ -444,98 +291,20 @@ func (d *demoTransit) batchCreateObjects(issuerId, classSuffix string) {
|
||||
for i := 0; i < 3; i++ {
|
||||
objectSuffix := strings.ReplaceAll(uuid.New().String(), "-", "_")
|
||||
|
||||
batchObject := fmt.Sprintf(`
|
||||
{
|
||||
"classId": "%s.%s",
|
||||
"passengerNames": "Passenger names",
|
||||
"heroImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Hero image description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg"
|
||||
}
|
||||
},
|
||||
"ticketLeg": {
|
||||
"destinationStationCode": "SFO",
|
||||
"destinationName": {
|
||||
"defaultValue": {
|
||||
"value": "Destination name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"arrivalDateTime": "2020-04-12T20:20:50.52Z",
|
||||
"originStationCode": "LA",
|
||||
"originName": {
|
||||
"defaultValue": {
|
||||
"value": "Origin name",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"departureDateTime": "2020-04-12T16:20:50.52Z",
|
||||
"fareName": {
|
||||
"defaultValue": {
|
||||
"value": "Fare name",
|
||||
"language": "en-US"
|
||||
}
|
||||
}
|
||||
},
|
||||
"barcode": {
|
||||
"type": "QR_CODE",
|
||||
"value": "QR code"
|
||||
},
|
||||
"locations": [
|
||||
{
|
||||
"latitude": 37.424015499999996,
|
||||
"longitude": -122.09259560000001
|
||||
}
|
||||
],
|
||||
"passengerType": "SINGLE_PASSENGER",
|
||||
"state": "ACTIVE",
|
||||
"linksModuleData": {
|
||||
"uris": [
|
||||
{
|
||||
"id": "LINK_MODULE_URI_ID",
|
||||
"uri": "http://maps.google.com/",
|
||||
"description": "Link module URI description"
|
||||
},
|
||||
{
|
||||
"id": "LINK_MODULE_TEL_ID",
|
||||
"uri": "tel:6505555555",
|
||||
"description": "Link module tel description"
|
||||
}
|
||||
]
|
||||
},
|
||||
"imageModulesData": [
|
||||
{
|
||||
"id": "IMAGE_MODULE_ID",
|
||||
"mainImage": {
|
||||
"contentDescription": {
|
||||
"defaultValue": {
|
||||
"value": "Image module description",
|
||||
"language": "en-US"
|
||||
}
|
||||
},
|
||||
"sourceUri": {
|
||||
"uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"textModulesData": [
|
||||
{
|
||||
"body": "Text module body",
|
||||
"header": "Text module header",
|
||||
"id": "TEXT_MODULE_ID"
|
||||
}
|
||||
],
|
||||
"tripType": "ONE_WAY",
|
||||
"id": "%s.%s"
|
||||
transitObject := new(walletobjects.TransitObject)
|
||||
transitObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix)
|
||||
transitObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix)
|
||||
transitObject.State = "ACTIVE"
|
||||
transitObject.PassengerNames = "Passenger names"
|
||||
transitObject.TripType = "ONE_WAY"
|
||||
transitObject.PassengerType = "SINGLE_PASSENGER"
|
||||
transitObject.TicketLeg = &walletobjects.TicketLeg{
|
||||
DestinationStationCode: "SFO",
|
||||
OriginStationCode: "LA",
|
||||
}
|
||||
`, issuerId, classSuffix, issuerId, objectSuffix)
|
||||
|
||||
transitJson, _ := json.Marshal(transitObject)
|
||||
batchObject := fmt.Sprintf("%s", transitJson)
|
||||
|
||||
data += "--batch_createobjectbatch\n"
|
||||
data += "Content-Type: application/json\n\n"
|
||||
@@ -544,8 +313,7 @@ func (d *demoTransit) batchCreateObjects(issuerId, classSuffix string) {
|
||||
}
|
||||
data += "--batch_createobjectbatch--"
|
||||
|
||||
// batchUrl = 'https://walletobjects.googleapis.com/batch';
|
||||
res, err := d.httpClient.Post(batchUrl, "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
res, err := d.credentials.Client(oauth2.NoContext).Post("https://walletobjects.googleapis.com/batch", "multipart/mixed; boundary=batch_createobjectbatch", bytes.NewBuffer([]byte(data)))
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
@@ -558,11 +326,6 @@ func (d *demoTransit) batchCreateObjects(issuerId, classSuffix string) {
|
||||
// [END batch]
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 0 {
|
||||
fmt.Println("Usage: go run demo_transit.go <issuer-id>")
|
||||
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)
|
||||
@@ -574,6 +337,6 @@ func main() {
|
||||
d.createObject(issuerId, classSuffix, objectSuffix)
|
||||
d.expireObject(issuerId, objectSuffix)
|
||||
d.createJwtNewObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.createJwtExistingObjects(issuerId)
|
||||
d.createJwtExistingObjects(issuerId, classSuffix, objectSuffix)
|
||||
d.batchCreateObjects(issuerId, classSuffix)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user