From 5a1ab2a4556ad00825d6db6425c999a9d96e520e Mon Sep 17 00:00:00 2001 From: Nick Alteen Date: Thu, 1 Sep 2022 13:11:25 -0400 Subject: [PATCH] Addition of batch pass creation examples * Updated .NET and Java file names to be consistent * Corrected indentation in .NET files * Added missing quotes in HTTP request bodies * Updated gradle version for Java examples * Added missing JSON conversion for Java HTTP requests * Added code to generate batch statements --- .gitignore | 10 + README.md | 4 +- dotnet/DemoEventticket.cs | 211 ++++- dotnet/DemoFlight.cs | 175 +++- dotnet/DemoGeneric.cs | 188 +++- dotnet/DemoGiftcard.cs | 176 +++- dotnet/DemoLoyalty.cs | 175 +++- dotnet/DemoOffer.cs | 176 +++- dotnet/DemoTransit.cs | 230 ++++- dotnet/wallet-rest-samples.csproj | 4 +- http/demo_eventticket.http | 4 +- http/demo_flight.http | 4 +- http/demo_generic.http | 4 +- http/demo_giftcard.http | 4 +- http/demo_loyalty.http | 4 +- http/demo_offer.http | 4 +- http/demo_transit.http | 4 +- java/build.gradle | 10 +- java/gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 60756 bytes java/gradle/wrapper/gradle-wrapper.properties | 2 +- java/gradlew | 275 +++--- java/gradlew.bat | 14 +- java/settings.gradle | 1 - java/src/main/java/DemoEventticket.java | 81 +- java/src/main/java/DemoFlight.java | 81 +- java/src/main/java/DemoGeneric.java | 80 +- java/src/main/java/DemoGiftcard.java | 82 +- java/src/main/java/DemoLoyalty.java | 79 +- java/src/main/java/DemoOffer.java | 79 +- java/src/main/java/DemoTransit.java | 80 +- nodejs/demo-eventticket.js | 155 +++- nodejs/demo-flight.js | 126 ++- nodejs/demo-generic.js | 135 ++- nodejs/demo-giftcard.js | 127 ++- nodejs/demo-loyalty.js | 126 ++- nodejs/demo-offer.js | 126 ++- nodejs/demo-transit.js | 170 +++- php/demo_eventticket.php | 48 +- php/demo_flight.php | 50 +- php/demo_generic.php | 49 +- php/demo_giftcard.php | 49 +- php/demo_loyalty.php | 48 +- php/demo_offer.php | 48 +- php/demo_transit.php | 49 +- python/demo_eventticket.py | 397 +++++--- python/demo_flight.py | 336 ++++--- python/demo_generic.py | 327 ++++--- python/demo_giftcard.py | 311 ++++--- python/demo_loyalty.py | 318 ++++--- python/demo_offer.py | 308 ++++--- python/demo_transit.py | 440 ++++++--- templates/generate.py | 865 +++++++++++------- templates/template.cs | 95 +- templates/template.java | 79 +- templates/template.js | 64 +- templates/template.php | 46 +- templates/template.py | 118 ++- 57 files changed, 5608 insertions(+), 1643 deletions(-) diff --git a/.gitignore b/.gitignore index c6129c8..1d4fc09 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .DS_Store .vscode *.code-workspace +testing/ # Node.js node_modules @@ -15,12 +16,18 @@ build local.properties .classpath .project +java/lib/ + +# See: https://developers.google.com/wallet/generic/resources/libraries +java/lib/libwalletobjects_public_java_lib_v1.jar # Python *.pyc __pycache__ .venv/ Pipfile.lock +*.yapf +.python-version # .NET bin @@ -32,6 +39,9 @@ obj vendor composer.lock +# See: https://developers.google.com/wallet/generic/resources/libraries +php/lib/Walletobjects.php + # Ruby Gemfile.lock diff --git a/README.md b/README.md index 1326177..88f21ff 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This project contains samples for using the [Google Wallet REST APIs](https://developers.google.com/wallet/) in the following languages: - Java -- C# +- C# - JavaScript (Node.js) - PHP - Python @@ -19,4 +19,4 @@ Each sample demonstrates the following: ## Contributing -Please note that the samples are automatically generated using templates found in the "templates" directory, where you will also find the "generate.py" script that generates the samples. If contributing any changes, please work on the files in this directory. \ No newline at end of file +Please note that the samples are automatically generated using templates found in the "templates" directory, where you will also find the "generate.py" script that generates the samples. If contributing any changes, please work on the files in this directory. diff --git a/dotnet/DemoEventticket.cs b/dotnet/DemoEventticket.cs index 8ca8464..928693e 100644 --- a/dotnet/DemoEventticket.cs +++ b/dotnet/DemoEventticket.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-eventTicket-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -96,7 +98,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -268,6 +270,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -331,3 +334,165 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + kind = "walletobjects#barcode", + type = "qrCode", + value = "Test QR Code" + }, + state = "active", + seatInfo = new + { + kind = "walletobjects#eventSeat", + seat = new + { + kind = "walletobjects#localizedString", + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "42" + } + }, + row = new + { + kind = "walletobjects#localizedString", + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "G3" + } + }, + section = new + { + kind = "walletobjects#localizedString", + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "5" + } + }, + gate = new + { + kind = "walletobjects#localizedString", + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "A" + } + } + }, + ticketHolderName = "Test ticket holder name", + ticketNumber = "Test ticket number", + locations = new object[] + { + new + { + kind = "walletobjects#latLongPoint", + latitude = 37.424015499999996, + longitude = -122.09259560000001 + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/eventTicketObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/DemoFlight.cs b/dotnet/DemoFlight.cs index 822711f..4048bbe 100644 --- a/dotnet/DemoFlight.cs +++ b/dotnet/DemoFlight.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-flight-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -109,7 +111,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -245,6 +247,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -308,3 +311,129 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + kind = "walletobjects#barcode", + type = "qrCode", + value = "Test QR Code" + }, + state = "active", + passengerName = "Test passenger name", + reservationInfo = new + { + confirmationCode = "Test confirmation code" + }, + boardingAndSeatingInfo = new + { + seatNumber = "42", + boardingGroup = "B" + }, + locations = new object[] + { + new + { + kind = "walletobjects#latLongPoint", + latitude = 37.424015499999996, + longitude = -122.09259560000001 + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/flightObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/DemoGeneric.cs b/dotnet/DemoGeneric.cs index f7a318a..b64481a 100644 --- a/dotnet/DemoGeneric.cs +++ b/dotnet/DemoGeneric.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-generic-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -87,7 +89,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -236,6 +238,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -299,3 +302,142 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + kind = "walletobjects#barcode", + type = "qrCode", + value = "Test QR Code" + }, + genericType = "GENERIC_TYPE_UNSPECIFIED", + hexBackgroundColor = "#4285f4", + logo = new + { + sourceUri = new + { + uri = "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" + } + }, + cardTitle = new + { + defaultValue = new + { + language = "en-US", + value = "Testing Generic Title" + } + }, + header = new + { + defaultValue = new + { + language = "en-US", + value = "Testing Generic Header" + } + }, + subheader = new + { + defaultValue = new + { + language = "en", + value = "Testing Generic Sub Header" + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/genericObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/DemoGiftcard.cs b/dotnet/DemoGiftcard.cs index 0cb54fb..dd98b31 100644 --- a/dotnet/DemoGiftcard.cs +++ b/dotnet/DemoGiftcard.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-giftCard-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -90,7 +92,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -227,6 +229,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -290,3 +293,130 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + kind = "walletobjects#barcode", + type = "qrCode", + value = "Test QR Code" + }, + cardNumber = "Test card number", + cardPin = "Test card pin", + balance = new + { + kind = "walletobjects#money", + micros = 20000000, + currencyCode = "USD" + }, + balanceUpdateTime = new + { + date = "2020-04-12T16:20:50.52Z" + }, + locations = new object[] + { + new + { + kind = "walletobjects#latLongPoint", + latitude = 37.424015499999996, + longitude = -122.09259560000001 + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/giftCardObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/DemoLoyalty.cs b/dotnet/DemoLoyalty.cs index 5850a0a..8ac7b94 100644 --- a/dotnet/DemoLoyalty.cs +++ b/dotnet/DemoLoyalty.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-loyalty-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -98,7 +100,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -234,6 +236,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -297,3 +300,129 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + kind = "walletobjects#barcode", + type = "qrCode", + value = "Test QR Code" + }, + state = "active", + accountId = "Test account id", + accountName = "Test account name", + loyaltyPoints = new + { + balance = new + { + @string = "800" + }, + label = "Points" + }, + locations = new object[] + { + new + { + kind = "walletobjects#latLongPoint", + latitude = 37.424015499999996, + longitude = -122.09259560000001 + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/loyaltyObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/DemoOffer.cs b/dotnet/DemoOffer.cs index b3476e9..4349e86 100644 --- a/dotnet/DemoOffer.cs +++ b/dotnet/DemoOffer.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-offer-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -91,7 +93,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -228,6 +230,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -291,3 +294,130 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + type = "qrCode", + value = "Testing Offers QR Code" + }, + state = "active", + validTimeInterval = new + { + kind = "walletobjects#timeInterval", + start = new + { + date = "2023-06-12T23:20:50.52Z" + }, + end = new + { + date = "2023-12-12T23:20:50.52Z" + } + }, + locations = new object[] + { + new + { + kind = "walletobjects#latLongPoint", + latitude = 37.424015499999996, + longitude = -122.09259560000001 + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/offerObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/DemoTransit.cs b/dotnet/DemoTransit.cs index 1443200..f30a584 100644 --- a/dotnet/DemoTransit.cs +++ b/dotnet/DemoTransit.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-transit-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -99,7 +101,7 @@ var classPayload = new HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -290,6 +292,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -353,3 +356,184 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = new + { + id = objectId, + classId = $"{issuerId}.{classId}", + heroImage = new + { + sourceUri = new + { + uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + description = "Test heroImage description" + } + }, + textModulesData = new object[] + { + new + { + header = "Test text module header", + body = "Test text module body" + } + }, + linksModuleData = new + { + uris = new object[] + { + new + { + kind = "walletobjects#uri", + uri = "http://maps.google.com/", + description = "Test link module uri description" + }, + new + { + kind = "walletobjects#uri", + uri = "tel:6505555555", + description = "Test link module tel description" + } + } + }, + imageModulesData = new object[] + { + new + { + mainImage = new + { + kind = "walletobjects#image", + sourceUri = new + { + kind = "walletobjects#uri", + uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + description = "Test image module description" + } + } + } + }, + barcode = new + { + kind = "walletobjects#barcode", + type = "qrCode", + value = "Test QR Code" + }, + passengerType = "singlePassenger", + passengerNames = "Test passenger names", + ticketLeg = new + { + originStationCode = "LA", + originName = new + { + kind = "walletobjects#localizedString", + translatedValues = new object[] + { + new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "Test translated origin name" + } + }, + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "Test default origin name" + } + }, + destinationStationCode = "SFO", + destinationName = new + { + kind = "walletobjects#localizedString", + translatedValues = new object[] + { + new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "Test translated destination name" + } + }, + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "Test default destination name" + } + }, + departureDateTime = "2020-04-12T16:20:50.52Z", + arrivalDateTime = "2020-04-12T20:20:50.52Z", + fareName = new + { + kind = "walletobjects#localizedString", + translatedValues = new object[] + { + new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "Test translated fare name" + } + }, + defaultValue = new + { + kind = "walletobjects#translatedString", + language = "en-us", + value = "Test default fare name" + } + } + }, + locations = new object[] + { + new + { + kind = "walletobjects#latLongPoint", + latitude = 37.424015499999996, + longitude = -122.09259560000001 + } + } + }; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/transitObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/dotnet/wallet-rest-samples.csproj b/dotnet/wallet-rest-samples.csproj index 5847841..49466bb 100644 --- a/dotnet/wallet-rest-samples.csproj +++ b/dotnet/wallet-rest-samples.csproj @@ -3,9 +3,9 @@ Exe net6.0 - wallet_rest_samples enable - enable + wallet_rest_samples + disable diff --git a/http/demo_eventticket.http b/http/demo_eventticket.http index 5824b40..20f9683 100644 --- a/http/demo_eventticket.http +++ b/http/demo_eventticket.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/http/demo_flight.http b/http/demo_flight.http index 4df867f..3d3b6d7 100644 --- a/http/demo_flight.http +++ b/http/demo_flight.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/http/demo_generic.http b/http/demo_generic.http index ffe6292..8b4d8c2 100644 --- a/http/demo_generic.http +++ b/http/demo_generic.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/http/demo_giftcard.http b/http/demo_giftcard.http index b529678..747a53a 100644 --- a/http/demo_giftcard.http +++ b/http/demo_giftcard.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/http/demo_loyalty.http b/http/demo_loyalty.http index 7330203..1b11ff7 100644 --- a/http/demo_loyalty.http +++ b/http/demo_loyalty.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/http/demo_offer.http b/http/demo_offer.http index 86f3bd6..872ae7c 100644 --- a/http/demo_offer.http +++ b/http/demo_offer.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/http/demo_transit.http b/http/demo_transit.http index 4bb544e..7cf42cf 100644 --- a/http/demo_transit.http +++ b/http/demo_transit.http @@ -8,8 +8,8 @@ Accept-Encoding: gzip, deflate Connection: Keep-Alive { - "id": issuer-id.user-id, - "classId": issuer-id.class-id, + "id": "issuer-id.user-id", + "classId": "issuer-id.class-id", "heroImage": { "sourceUri": { "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", diff --git a/java/build.gradle b/java/build.gradle index 4a2f889..c064628 100644 --- a/java/build.gradle +++ b/java/build.gradle @@ -10,11 +10,15 @@ repositories { } dependencies { + // Replace with path to your local download of the Google Wallet library + implementation files('lib/libwalletobjects_public_java_lib_v1.jar') + implementation 'com.auth0:java-jwt:3.19.1' implementation 'com.auth0:jwks-rsa:0.9.0' implementation 'com.google.apis:google-api-services-oauth2:v1-rev20190313-1.30.3' - implementation 'com.google.api-client:google-api-client:2.0.0' + implementation 'com.google.api-client:google-api-client:1.25.0' implementation 'com.google.auth:google-auth-library-oauth2-http:1.10.0' - implementation 'com.google.guava:guava:r05' - implementation 'com.google.api-client:google-api-client:1.19.1' + implementation 'com.squareup.okhttp3:okhttp:4.3.1' + implementation 'javax.json:javax.json-api:1.1' + implementation 'org.glassfish:javax.json:1.1' } diff --git a/java/gradle/wrapper/gradle-wrapper.jar b/java/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..249e5832f090a2944b7473328c07c9755baa3196 100644 GIT binary patch delta 10158 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 delta 9041 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 diff --git a/java/gradle/wrapper/gradle-wrapper.properties b/java/gradle/wrapper/gradle-wrapper.properties index 69a9715..ae04661 100644 --- a/java/gradle/wrapper/gradle-wrapper.properties +++ b/java/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/java/gradlew b/java/gradlew index 744e882..a69d9cb 100755 --- a/java/gradlew +++ b/java/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,101 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=`expr $i + 1` - done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/java/gradlew.bat b/java/gradlew.bat index ac1b06f..53a6b23 100644 --- a/java/gradlew.bat +++ b/java/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/java/settings.gradle b/java/settings.gradle index 791d241..de0756f 100644 --- a/java/settings.gradle +++ b/java/settings.gradle @@ -1,2 +1 @@ rootProject.name = 'wallet-samples' - diff --git a/java/src/main/java/DemoEventticket.java b/java/src/main/java/DemoEventticket.java index b9c676c..905eeee 100644 --- a/java/src/main/java/DemoEventticket.java +++ b/java/src/main/java/DemoEventticket.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,9 +35,14 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] -public class DemoEventticket { +public class DemoEventTicket { public static void main(String[] args) throws Exception { /* * keyFilePath - Path to service account key file from Google Cloud Console @@ -70,10 +78,12 @@ public class DemoEventticket { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -333,10 +343,73 @@ public class DemoEventticket { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(EventTicketObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + EventTicketObject eventTicketObject = new EventTicketObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject + .setId(objectId) + .setClassId(classId) + .setState("ACTIVE");; + + client.eventticketobject().insert(eventTicketObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/java/src/main/java/DemoFlight.java b/java/src/main/java/DemoFlight.java index 4f4c408..2d04833 100644 --- a/java/src/main/java/DemoFlight.java +++ b/java/src/main/java/DemoFlight.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,6 +35,11 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] public class DemoFlight { @@ -70,10 +78,12 @@ public class DemoFlight { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -315,10 +325,75 @@ public class DemoFlight { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(FlightObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + FlightObject flightObject = new FlightObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject + .setId(objectId) + .setClassId(classId) + .setState("ACTIVE") + .setPassengerName("NAME") + .setReservationInfo(new ReservationInfo());; + + client.flightobject().insert(flightObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/java/src/main/java/DemoGeneric.java b/java/src/main/java/DemoGeneric.java index b1d4f4e..05050f3 100644 --- a/java/src/main/java/DemoGeneric.java +++ b/java/src/main/java/DemoGeneric.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,6 +35,11 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] public class DemoGeneric { @@ -70,10 +78,12 @@ public class DemoGeneric { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -306,10 +316,74 @@ public class DemoGeneric { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(GenericObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + GenericObject genericObject = new GenericObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericobject + .setId(objectId) + .setClassId(classId) + .setCardTitle(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage("en-US").setValue("TITLE"))) + .setHeader(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage("en-US").setValue("HEADER")));; + + client.genericobject().insert(genericObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/java/src/main/java/DemoGiftcard.java b/java/src/main/java/DemoGiftcard.java index 82f2071..16d9ab3 100644 --- a/java/src/main/java/DemoGiftcard.java +++ b/java/src/main/java/DemoGiftcard.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,9 +35,14 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] -public class DemoGiftcard { +public class DemoGiftCard { public static void main(String[] args) throws Exception { /* * keyFilePath - Path to service account key file from Google Cloud Console @@ -70,10 +78,12 @@ public class DemoGiftcard { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -301,10 +311,74 @@ public class DemoGiftcard { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(GiftCardObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + GiftCardObject giftCardObject = new GiftCardObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject + .setId(objectId) + .setClassId(classId) + .setState("ACTIVE") + .setCardNumber("CARD_NUMBER");; + + client.giftcardobject().insert(giftCardObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/java/src/main/java/DemoLoyalty.java b/java/src/main/java/DemoLoyalty.java index c445880..47ce37d 100644 --- a/java/src/main/java/DemoLoyalty.java +++ b/java/src/main/java/DemoLoyalty.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,6 +35,11 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] public class DemoLoyalty { @@ -70,10 +78,12 @@ public class DemoLoyalty { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -306,10 +316,73 @@ public class DemoLoyalty { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(LoyaltyObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + LoyaltyObject loyaltyObject = new LoyaltyObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject + .setId(objectId) + .setClassId(classId) + .setState("ACTIVE");; + + client.loyaltyobject().insert(loyaltyObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/java/src/main/java/DemoOffer.java b/java/src/main/java/DemoOffer.java index ea06571..51d27c5 100644 --- a/java/src/main/java/DemoOffer.java +++ b/java/src/main/java/DemoOffer.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,6 +35,11 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] public class DemoOffer { @@ -70,10 +78,12 @@ public class DemoOffer { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -301,10 +311,73 @@ public class DemoOffer { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(OfferObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + OfferObject offerObject = new OfferObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject + .setId(objectId) + .setClassId(classId) + .setState("ACTIVE");; + + client.offerobject().insert(offerObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/java/src/main/java/DemoTransit.java b/java/src/main/java/DemoTransit.java index 5a93e5e..41c8056 100644 --- a/java/src/main/java/DemoTransit.java +++ b/java/src/main/java/DemoTransit.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,6 +35,11 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] public class DemoTransit { @@ -70,10 +78,12 @@ public class DemoTransit { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -351,10 +361,74 @@ public class DemoTransit { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback callback = new JsonBatchCallback() { + // Invoked if the request was successful + public void onSuccess(TransitObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + TransitObject transitObject = new TransitObject() + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject + .setId(objectId) + .setClassId(classId) + .setState("ACTIVE") + .setTripType("ONE_WAY");; + + client.transitobject().insert(transitObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/nodejs/demo-eventticket.js b/nodejs/demo-eventticket.js index 4036406..37346fc 100644 --- a/nodejs/demo-eventticket.js +++ b/nodejs/demo-eventticket.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -192,8 +194,8 @@ async function main() { } ] }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -217,7 +219,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -245,13 +247,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -284,8 +286,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -298,4 +300,137 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "seatInfo": { + "kind": "walletobjects#eventSeat", + "seat": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "42" + } + }, + "row": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "G3" + } + }, + "section": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "5" + } + }, + "gate": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "A" + } + } + }, + "ticketHolderName": "Test ticket holder name", + "ticketNumber": "Test ticket number", + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/eventTicketObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/nodejs/demo-flight.js b/nodejs/demo-flight.js index 3c0a810..311efef 100644 --- a/nodejs/demo-flight.js +++ b/nodejs/demo-flight.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -174,8 +176,8 @@ async function main() { } ] }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -199,7 +201,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -227,13 +229,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -266,8 +268,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -280,4 +282,108 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "passengerName": "Test passenger name", + "reservationInfo": { + "confirmationCode": "Test confirmation code" + }, + "boardingAndSeatingInfo": { + "seatNumber": "42", + "boardingGroup": "B" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/flightObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/nodejs/demo-generic.js b/nodejs/demo-generic.js index 7707f5f..7f00eae 100644 --- a/nodejs/demo-generic.js +++ b/nodejs/demo-generic.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -165,8 +167,8 @@ async function main() { } } }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -190,7 +192,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -218,13 +220,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -257,8 +259,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -271,4 +273,117 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "genericType": "GENERIC_TYPE_UNSPECIFIED", + "hexBackgroundColor": "#4285f4", + "logo": { + "sourceUri": { + "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" + } + }, + "cardTitle": { + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Title" + } + }, + "header": { + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Header" + } + }, + "subheader": { + "defaultValue": { + "language": "en", + "value": "Testing Generic Sub Header" + } + } + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/genericObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/nodejs/demo-giftcard.js b/nodejs/demo-giftcard.js index 23d1130..029634c 100644 --- a/nodejs/demo-giftcard.js +++ b/nodejs/demo-giftcard.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -160,8 +162,8 @@ async function main() { } ] }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -185,7 +187,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -213,13 +215,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -252,8 +254,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -266,4 +268,109 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "cardNumber": "Test card number", + "cardPin": "Test card pin", + "balance": { + "kind": "walletobjects#money", + "micros": 20000000, + "currencyCode": "USD" + }, + "balanceUpdateTime": { + "date": "2020-04-12T16:20:50.52Z" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/giftCardObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/nodejs/demo-loyalty.js b/nodejs/demo-loyalty.js index 207d8c0..fe27e34 100644 --- a/nodejs/demo-loyalty.js +++ b/nodejs/demo-loyalty.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -165,8 +167,8 @@ async function main() { } ] }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -190,7 +192,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -218,13 +220,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -257,8 +259,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -271,4 +273,108 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "accountId": "Test account id", + "accountName": "Test account name", + "loyaltyPoints": { + "balance": { + "string": "800" + }, + "label": "Points" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/loyaltyObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/nodejs/demo-offer.js b/nodejs/demo-offer.js index 8cfb119..0466af6 100644 --- a/nodejs/demo-offer.js +++ b/nodejs/demo-offer.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -160,8 +162,8 @@ async function main() { } ] }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -185,7 +187,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -213,13 +215,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -252,8 +254,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -266,4 +268,108 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "type": "qrCode", + "value": "Testing Offers QR Code" + }, + "state": "active", + "validTimeInterval": { + "kind": "walletobjects#timeInterval", + "start": { + "date": "2023-06-12T23:20:50.52Z" + }, + "end": { + "date": "2023-12-12T23:20:50.52Z" + } + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/offerObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/nodejs/demo-transit.js b/nodejs/demo-transit.js index 147d483..109bbbb 100644 --- a/nodejs/demo-transit.js +++ b/nodejs/demo-transit.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -210,8 +212,8 @@ async function main() { } ] }; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -235,7 +237,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -263,13 +265,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -302,8 +304,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -316,4 +318,152 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = { + "id": objectId, + "classId": `${issuerId}.${classId}`, + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "passengerType": "singlePassenger", + "passengerNames": "Test passenger names", + "ticketLeg": { + "originStationCode": "LA", + "originName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated origin name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default origin name" + } + }, + "destinationStationCode": "SFO", + "destinationName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated destination name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default destination name" + } + }, + "departureDateTime": "2020-04-12T16:20:50.52Z", + "arrivalDateTime": "2020-04-12T20:20:50.52Z", + "fareName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated fare name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default fare name" + } + } + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + }; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/transitObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/php/demo_eventticket.php b/php/demo_eventticket.php index 38c0642..5ddd40d 100644 --- a/php/demo_eventticket.php +++ b/php/demo_eventticket.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -310,3 +312,47 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $eventTicketObject = new Google_Service_Walletobjects_EventTicketObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/events/rest/v1/eventticketobject + $eventTicketObject->setId($objectId); + $eventTicketObject->setClassId("$issuerId.$classId"); + $eventTicketObject->setState("ACTIVE"); + + $batch->add($service->eventticketobject->insert($eventTicketObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/php/demo_flight.php b/php/demo_flight.php index 356eaa6..3d581ba 100644 --- a/php/demo_flight.php +++ b/php/demo_flight.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -292,3 +294,49 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $flightObject = new Google_Service_Walletobjects_FlightObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/boarding-passes/rest/v1/flightobject + $flightObject->setId($objectId); + $flightObject->setClassId("$issuerId.$classId"); + $flightObject->setState("ACTIVE"); + $flightObject->setPassengerName("NAME"); + $flightObject->setReservationInfo(new Google_Service_Walletobjects_ReservationInfo()); + + $batch->add($service->flightobject->insert($flightObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/php/demo_generic.php b/php/demo_generic.php index 06a298e..2ab66a1 100644 --- a/php/demo_generic.php +++ b/php/demo_generic.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -283,3 +285,48 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $genericObject = new Google_Service_Walletobjects_GenericObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/generic/rest/v1/genericobject + $genericObject->setId($objectId); + $genericObject->setClassId("$issuerId.$classId"); + $genericObject->setCardTitle(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage("en-US").setValue("TITLE"))); + $genericObject->setHeader(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage("en-US").setValue("HEADER"))); + + $batch->add($service->genericobject->insert($genericObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/php/demo_giftcard.php b/php/demo_giftcard.php index 39ed8d9..46a5c93 100644 --- a/php/demo_giftcard.php +++ b/php/demo_giftcard.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -278,3 +280,48 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $giftCardObject = new Google_Service_Walletobjects_GiftCardObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/gift-cards/rest/v1/giftcardobject + $giftCardObject->setId($objectId); + $giftCardObject->setClassId("$issuerId.$classId"); + $giftCardObject->setState("ACTIVE"); + $giftCardObject->setCardNumber("CARD_NUMBER"); + + $batch->add($service->giftcardobject->insert($giftCardObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/php/demo_loyalty.php b/php/demo_loyalty.php index 5b967da..78e8f2e 100644 --- a/php/demo_loyalty.php +++ b/php/demo_loyalty.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -283,3 +285,47 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $loyaltyObject = new Google_Service_Walletobjects_LoyaltyObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/loyalty-cards/rest/v1/loyaltyobject + $loyaltyObject->setId($objectId); + $loyaltyObject->setClassId("$issuerId.$classId"); + $loyaltyObject->setState("ACTIVE"); + + $batch->add($service->loyaltyobject->insert($loyaltyObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/php/demo_offer.php b/php/demo_offer.php index 9306531..d5971ce 100644 --- a/php/demo_offer.php +++ b/php/demo_offer.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -278,3 +280,47 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $offerObject = new Google_Service_Walletobjects_OfferObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/retail/offers/rest/v1/offerobject + $offerObject->setId($objectId); + $offerObject->setClassId("$issuerId.$classId"); + $offerObject->setState("ACTIVE"); + + $batch->add($service->offerobject->insert($offerObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/php/demo_transit.php b/php/demo_transit.php index 47265cb..8746a52 100644 --- a/php/demo_transit.php +++ b/php/demo_transit.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -328,3 +330,48 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $transitObject = new Google_Service_Walletobjects_TransitObject(); + // See link below for more information on required properties + // https://developers.google.com/wallet/tickets/transit-passes/qr-code/rest/v1/transitobject + $transitObject->setId($objectId); + $transitObject->setClassId("$issuerId.$classId"); + $transitObject->setState("ACTIVE"); + $transitObject->setTripType("ONE_WAY"); + + $batch->add($service->transitobject->insert($transitObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/python/demo_eventticket.py b/python/demo_eventticket.py index 0e62a11..dc53e41 100644 --- a/python/demo_eventticket.py +++ b/python/demo_eventticket.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-eventTicket-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,20 +70,20 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/eventTicketClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name", - "eventName": { - "defaultValue": { - "language": "en-US", - "value": "Test event name" - } - }, - "reviewStatus": "underReview" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name", + "eventName": { + "defaultValue": { + "language": "en-US", + "value": "Test event name" + } + }, + "reviewStatus": "underReview" } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -92,106 +95,106 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/eventTicketObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" } - } - } - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code" - }, - "state": "active", - "seatInfo": { - "kind": "walletobjects#eventSeat", - "seat": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "42" - } }, - "row": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "G3" - } + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] }, - "section": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "5" - } + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" }, - "gate": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "A" - } - } - }, - "ticketHolderName": "Test ticket holder name", - "ticketNumber": "Test ticket number", - "locations": [ - { - "kind": "walletobjects#latLongPoint", - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ] + "state": "active", + "seatInfo": { + "kind": "walletobjects#eventSeat", + "seat": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "42" + } + }, + "row": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "G3" + } + }, + "section": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "5" + } + }, + "gate": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "A" + } + } + }, + "ticketHolderName": "Test ticket holder name", + "ticketNumber": "Test ticket number", + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -202,17 +205,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "eventTicketObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "eventTicketObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -238,16 +241,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -263,20 +266,150 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "seatInfo": { + "kind": "walletobjects#eventSeat", + "seat": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "42" + } + }, + "row": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "G3" + } + }, + "section": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "5" + } + }, + "gate": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "A" + } + } + }, + "ticketHolderName": "Test ticket holder name", + "ticketNumber": "Test ticket number", + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/eventTicketObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/python/demo_flight.py b/python/demo_flight.py index 02b2957..ff9d48f 100644 --- a/python/demo_flight.py +++ b/python/demo_flight.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-flight-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,31 +70,31 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/flightClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name", - "destination": { - "airportIataCode": "SFO", - "gate": "C3", - "terminal": "2" - }, - "flightHeader": { - "carrier": { - "carrierIataCode": "LX" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name", + "destination": { + "airportIataCode": "SFO", + "gate": "C3", + "terminal": "2" }, - "flightNumber": "123" - }, - "origin": { - "airportIataCode": "LAX", - "gate": "A2", - "terminal": "1" - }, - "localScheduledDepartureDateTime": "2023-07-02T15:30:00", - "reviewStatus": "underReview" + "flightHeader": { + "carrier": { + "carrierIataCode": "LX" + }, + "flightNumber": "123" + }, + "origin": { + "airportIataCode": "LAX", + "gate": "A2", + "terminal": "1" + }, + "localScheduledDepartureDateTime": "2023-07-02T15:30:00", + "reviewStatus": "underReview" } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -103,77 +106,77 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/flightObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" } - } - } - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code" - }, - "state": "active", - "passengerName": "Test passenger name", - "reservationInfo": { - "confirmationCode": "Test confirmation code" - }, - "boardingAndSeatingInfo": { - "seatNumber": "42", - "boardingGroup": "B" - }, - "locations": [ - { - "kind": "walletobjects#latLongPoint", - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ] + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "passengerName": "Test passenger name", + "reservationInfo": { + "confirmationCode": "Test confirmation code" + }, + "boardingAndSeatingInfo": { + "seatNumber": "42", + "boardingGroup": "B" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -184,17 +187,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "flightObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "flightObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -220,16 +223,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -245,20 +248,121 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "passengerName": "Test passenger name", + "reservationInfo": { + "confirmationCode": "Test confirmation code" + }, + "boardingAndSeatingInfo": { + "seatNumber": "42", + "boardingGroup": "B" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/flightObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/python/demo_generic.py b/python/demo_generic.py index 6f9cf24..b7adebd 100644 --- a/python/demo_generic.py +++ b/python/demo_generic.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-generic-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,13 +70,13 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/genericClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name" } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -85,86 +88,86 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/genericObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "genericType": "GENERIC_TYPE_UNSPECIFIED", + "hexBackgroundColor": "#4285f4", + "logo": { + "sourceUri": { + "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" + } + }, + "cardTitle": { + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Title" + } + }, + "header": { + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Header" + } + }, + "subheader": { + "defaultValue": { + "language": "en", + "value": "Testing Generic Sub Header" } - } } - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code" - }, - "genericType": "GENERIC_TYPE_UNSPECIFIED", - "hexBackgroundColor": "#4285f4", - "logo": { - "sourceUri": { - "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" - } - }, - "cardTitle": { - "defaultValue": { - "language": "en-US", - "value": "Testing Generic Title" - } - }, - "header": { - "defaultValue": { - "language": "en-US", - "value": "Testing Generic Header" - } - }, - "subheader": { - "defaultValue": { - "language": "en", - "value": "Testing Generic Sub Header" - } - } } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -175,17 +178,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "genericObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "genericObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -211,16 +214,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -236,20 +239,130 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "genericType": "GENERIC_TYPE_UNSPECIFIED", + "hexBackgroundColor": "#4285f4", + "logo": { + "sourceUri": { + "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" + } + }, + "cardTitle": { + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Title" + } + }, + "header": { + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Header" + } + }, + "subheader": { + "defaultValue": { + "language": "en", + "value": "Testing Generic Sub Header" + } + } + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/genericObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/python/demo_giftcard.py b/python/demo_giftcard.py index 5ba2304..e519d7b 100644 --- a/python/demo_giftcard.py +++ b/python/demo_giftcard.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-giftCard-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,16 +70,16 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/giftCardClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name", - "merchantName": "Test merchant name", - "allowMultipleUsersPerObject": "true", - "reviewStatus": "underReview" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name", + "merchantName": "Test merchant name", + "allowMultipleUsersPerObject": "true", + "reviewStatus": "underReview" } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -88,78 +91,78 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/giftCardObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" } - } - } - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code" - }, - "cardNumber": "Test card number", - "cardPin": "Test card pin", - "balance": { - "kind": "walletobjects#money", - "micros": 20000000, - "currencyCode": "USD" - }, - "balanceUpdateTime": { - "date": "2020-04-12T16:20:50.52Z" - }, - "locations": [ - { - "kind": "walletobjects#latLongPoint", - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ] + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "cardNumber": "Test card number", + "cardPin": "Test card pin", + "balance": { + "kind": "walletobjects#money", + "micros": 20000000, + "currencyCode": "USD" + }, + "balanceUpdateTime": { + "date": "2020-04-12T16:20:50.52Z" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -170,17 +173,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "giftCardObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "giftCardObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -206,16 +209,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -231,20 +234,122 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "cardNumber": "Test card number", + "cardPin": "Test card pin", + "balance": { + "kind": "walletobjects#money", + "micros": 20000000, + "currencyCode": "USD" + }, + "balanceUpdateTime": { + "date": "2020-04-12T16:20:50.52Z" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/giftCardObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/python/demo_loyalty.py b/python/demo_loyalty.py index a032e97..15e27fe 100644 --- a/python/demo_loyalty.py +++ b/python/demo_loyalty.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-loyalty-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,22 +70,22 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/loyaltyClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name", - "programName": "test program name", - "programLogo": { - "kind": "walletobjects#image", - "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg" - } - }, - "reviewStatus": "underReview" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name", + "programName": "test program name", + "programLogo": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg" + } + }, + "reviewStatus": "underReview" } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -94,77 +97,77 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/loyaltyObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" } - } - } - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code" - }, - "state": "active", - "accountId": "Test account id", - "accountName": "Test account name", - "loyaltyPoints": { - "balance": { - "string": "800" }, - "label": "Points" - }, - "locations": [ - { - "kind": "walletobjects#latLongPoint", - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ] + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "accountId": "Test account id", + "accountName": "Test account name", + "loyaltyPoints": { + "balance": { + "string": "800" + }, + "label": "Points" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -175,17 +178,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "loyaltyObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "loyaltyObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -211,16 +214,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -236,20 +239,121 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "state": "active", + "accountId": "Test account id", + "accountName": "Test account name", + "loyaltyPoints": { + "balance": { + "string": "800" + }, + "label": "Points" + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/loyaltyObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/python/demo_offer.py b/python/demo_offer.py index 274c6dd..77f1660 100644 --- a/python/demo_offer.py +++ b/python/demo_offer.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-offer-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,17 +70,17 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/offerClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name", - "provider": "test provider", - "reviewStatus": "underReview", - "title": "test title", - "redemptionChannel": "online" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name", + "provider": "test provider", + "reviewStatus": "underReview", + "title": "test title", + "redemptionChannel": "online" } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -89,77 +92,77 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/offerObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" } - } - } - ], - "barcode": { - "type": "qrCode", - "value": "Testing Offers QR Code" - }, - "state": "active", - "validTimeInterval": { - "kind": "walletobjects#timeInterval", - "start": { - "date": "2023-06-12T23:20:50.52Z" }, - "end": { - "date": "2023-12-12T23:20:50.52Z" - } - }, - "locations": [ - { - "kind": "walletobjects#latLongPoint", - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ] + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "type": "qrCode", + "value": "Testing Offers QR Code" + }, + "state": "active", + "validTimeInterval": { + "kind": "walletobjects#timeInterval", + "start": { + "date": "2023-06-12T23:20:50.52Z" + }, + "end": { + "date": "2023-12-12T23:20:50.52Z" + } + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -170,17 +173,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "offerObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "offerObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -206,16 +209,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -231,20 +234,121 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "type": "qrCode", + "value": "Testing Offers QR Code" + }, + "state": "active", + "validTimeInterval": { + "kind": "walletobjects#timeInterval", + "start": { + "date": "2023-06-12T23:20:50.52Z" + }, + "end": { + "date": "2023-12-12T23:20:50.52Z" + } + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/offerObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/python/demo_transit.py b/python/demo_transit.py index 4f61c42..7976b68 100644 --- a/python/demo_transit.py +++ b/python/demo_transit.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-transit-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -67,23 +70,23 @@ http_client = AuthorizedSession(credentials) # [START class] CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/transitClass/" class_payload = { - "id": f"{ISSUER_ID}.{CLASS_ID}", - "issuerName": "test issuer name", - "reviewStatus": "underReview", - "transitType": "bus", - "logo": { - "kind": "walletobjects#image", - "sourceUri": { - "kind": "walletobjects#uri", - "uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png", - "description": "Test logo description" + "id": f"{ISSUER_ID}.{CLASS_ID}", + "issuerName": "test issuer name", + "reviewStatus": "underReview", + "transitType": "bus", + "logo": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png", + "description": "Test logo description" + } } - } } class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -95,121 +98,121 @@ print("class POST response: ", class_response.text) # [START object] OBJECT_URL = "https://walletobjects.googleapis.com/walletobjects/v1/transitObject/" object_payload = { - "id": OBJECT_ID, - "classId": f"{ISSUER_ID}.{CLASS_ID}", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description" - } - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body" - } - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description" - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description" - } - ] - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description" + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" } - } - } - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code" - }, - "passengerType": "singlePassenger", - "passengerNames": "Test passenger names", - "ticketLeg": { - "originStationCode": "LA", - "originName": { - "kind": "walletobjects#localizedString", - "translatedValues": [ - { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test translated origin name" - } - ], - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test default origin name" - } }, - "destinationStationCode": "SFO", - "destinationName": { - "kind": "walletobjects#localizedString", - "translatedValues": [ + "textModulesData": [ { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test translated destination name" + "header": "Test text module header", + "body": "Test text module body" } - ], - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test default destination name" - } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] }, - "departureDateTime": "2020-04-12T16:20:50.52Z", - "arrivalDateTime": "2020-04-12T20:20:50.52Z", - "fareName": { - "kind": "walletobjects#localizedString", - "translatedValues": [ + "imageModulesData": [ { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test translated fare name" + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } } - ], - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test default fare name" - } - } - }, - "locations": [ - { - "kind": "walletobjects#latLongPoint", - "latitude": 37.424015499999996, - "longitude": -122.09259560000001 - } - ] + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "passengerType": "singlePassenger", + "passengerNames": "Test passenger names", + "ticketLeg": { + "originStationCode": "LA", + "originName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated origin name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default origin name" + } + }, + "destinationStationCode": "SFO", + "destinationName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated destination name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default destination name" + } + }, + "departureDateTime": "2020-04-12T16:20:50.52Z", + "arrivalDateTime": "2020-04-12T20:20:50.52Z", + "fareName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated fare name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default fare name" + } + } + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] } object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -220,17 +223,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "transitObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "transitObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -256,16 +259,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -281,20 +284,165 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = { + "id": OBJECT_ID, + "classId": f"{ISSUER_ID}.{CLASS_ID}", + "heroImage": { + "sourceUri": { + "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": "Test heroImage description" + } + }, + "textModulesData": [ + { + "header": "Test text module header", + "body": "Test text module body" + } + ], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description" + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description" + } + ] + }, + "imageModulesData": [ + { + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": "walletobjects#uri", + "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": "Test image module description" + } + } + } + ], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code" + }, + "passengerType": "singlePassenger", + "passengerNames": "Test passenger names", + "ticketLeg": { + "originStationCode": "LA", + "originName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated origin name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default origin name" + } + }, + "destinationStationCode": "SFO", + "destinationName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated destination name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default destination name" + } + }, + "departureDateTime": "2020-04-12T16:20:50.52Z", + "arrivalDateTime": "2020-04-12T20:20:50.52Z", + "fareName": { + "kind": "walletobjects#localizedString", + "translatedValues": [ + { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated fare name" + } + ], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default fare name" + } + } + }, + "locations": [ + { + "kind": "walletobjects#latLongPoint", + "latitude": 37.424015499999996, + "longitude": -122.09259560000001 + } + ] + } + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/transitObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch] diff --git a/templates/generate.py b/templates/generate.py index 12ccf7c..0eb9e2e 100644 --- a/templates/generate.py +++ b/templates/generate.py @@ -19,503 +19,660 @@ import os import json default_class_payload = { - "id": "$class_id", - "issuerName": "test issuer name", + "id": "$class_id", + "issuerName": "test issuer name", } default_object_payload = { - "id": "$object_id", - "classId": "$class_id", - "heroImage": { - "sourceUri": { - "uri": "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", - "description": "Test heroImage description", - }, - }, - "textModulesData": [ - { - "header": "Test text module header", - "body": "Test text module body", - }, - ], - "linksModuleData": { - "uris": [ - { - "kind": "walletobjects#uri", - "uri": "http://maps.google.com/", - "description": "Test link module uri description", - }, - { - "kind": "walletobjects#uri", - "uri": "tel:6505555555", - "description": "Test link module tel description", - }, - ], - }, - "imageModulesData": [ - { - "mainImage": { - "kind": "walletobjects#image", + "id": "$object_id", + "classId": "$class_id", + "heroImage": { "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", - "description": "Test image module description", + "uri": + "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg", + "description": + "Test heroImage description", }, - }, }, - ], - "barcode": { - "kind": "walletobjects#barcode", - "type": "qrCode", - "value": "Test QR Code", - }, + "textModulesData": [{ + "header": "Test text module header", + "body": "Test text module body", + },], + "linksModuleData": { + "uris": [ + { + "kind": "walletobjects#uri", + "uri": "http://maps.google.com/", + "description": "Test link module uri description", + }, + { + "kind": "walletobjects#uri", + "uri": "tel:6505555555", + "description": "Test link module tel description", + }, + ], + }, + "imageModulesData": [{ + "mainImage": { + "kind": "walletobjects#image", + "sourceUri": { + "kind": + "walletobjects#uri", + "uri": + "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg", + "description": + "Test image module description", + }, + }, + },], + "barcode": { + "kind": "walletobjects#barcode", + "type": "qrCode", + "value": "Test QR Code", + }, +} + +BASE_URL = "https://developers.google.com/wallet" + +url_map = { + "generic": "/generic/rest/v1/genericobject", + "offer": "/retail/offers/rest/v1/offerobject", + "loyalty": "/retail/loyalty-cards/rest/v1/loyaltyobject", + "giftCard": "/retail/gift-cards/rest/v1/giftcardobject", + "eventTicket": "/tickets/events/rest/v1/eventticketobject", + "flight": "/tickets/boarding-passes/rest/v1/flightobject", + "transit": "/tickets/transit-passes/qr-code/rest/v1/transitobject", } payloads = {} for object_type in [ - "generic", - "offer", - "loyalty", - "giftCard", - "eventTicket", - "flight", - "transit", + "generic", + "offer", + "loyalty", + "giftCard", + "eventTicket", + "flight", + "transit", ]: - payloads[object_type] = { - "$class_payload": dict(default_class_payload), - "$object_payload": dict(default_object_payload), - } + payloads[object_type] = { + "$class_payload": dict(default_class_payload), + "$object_payload": dict(default_object_payload), + } ################# # Generic ################# -payloads["generic"]["$object_payload"].update( - { +payloads["generic"]["$object_payload"].update({ "genericType": "GENERIC_TYPE_UNSPECIFIED", "hexBackgroundColor": "#4285f4", "logo": { - "sourceUri": { - "uri": "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" - } + "sourceUri": { + "uri": + "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" + } }, "cardTitle": { - "defaultValue": {"language": "en-US", "value": "Testing Generic Title"} + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Title" + } }, "header": { - "defaultValue": {"language": "en-US", "value": "Testing Generic Header"} + "defaultValue": { + "language": "en-US", + "value": "Testing Generic Header" + } }, "subheader": { - "defaultValue": {"language": "en", "value": "Testing Generic Sub Header"} + "defaultValue": { + "language": "en", + "value": "Testing Generic Sub Header" + } }, - } -) +}) ################# # Offer ################# -payloads["offer"]["$class_payload"].update( - { +payloads["offer"]["$class_payload"].update({ "provider": "test provider", "reviewStatus": "underReview", "title": "test title", "redemptionChannel": "online", - } -) +}) -payloads["offer"]["$object_payload"].update( - { - "state": "active", +payloads["offer"]["$object_payload"].update({ + "state": + "active", "barcode": { - "type": "qrCode", - "value": "Testing Offers QR Code" + "type": "qrCode", + "value": "Testing Offers QR Code" }, "validTimeInterval": { - "kind": "walletobjects#timeInterval", - "start": { - "date": "2023-06-12T23:20:50.52Z" - }, - "end": { - "date": "2023-12-12T23:20:50.52Z" - }, + "kind": "walletobjects#timeInterval", + "start": { + "date": "2023-06-12T23:20:50.52Z" + }, + "end": { + "date": "2023-12-12T23:20:50.52Z" + }, }, - "locations": [ - { + "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001, - } - ], - } -) + }], +}) ################# # Loyalty ################# -payloads["loyalty"]["$class_payload"].update( - { +payloads["loyalty"]["$class_payload"].update({ "programName": "test program name", "programLogo": { - "kind": "walletobjects#image", - "sourceUri": { - "kind": "walletobjects#uri", - "uri": "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg", - }, + "kind": "walletobjects#image", + "sourceUri": { + "kind": + "walletobjects#uri", + "uri": + "http://farm8.staticflickr.com/7340/11177041185_a61a7f2139_o.jpg", + }, }, "reviewStatus": "underReview", - } -) +}) -payloads["loyalty"]["$object_payload"].update( - { - "state": "active", - "accountId": "Test account id", - "accountName": "Test account name", +payloads["loyalty"]["$object_payload"].update({ + "state": + "active", + "accountId": + "Test account id", + "accountName": + "Test account name", "loyaltyPoints": { - "balance": {"string": "800"}, - "label": "Points", + "balance": { + "string": "800" + }, + "label": "Points", }, - "locations": [ - { + "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001, - } - ], - } -) + }], +}) ################# # GiftCard ################# -payloads["giftCard"]["$class_payload"].update( - { +payloads["giftCard"]["$class_payload"].update({ "merchantName": "Test merchant name", "allowMultipleUsersPerObject": "true", "reviewStatus": "underReview", - } -) +}) -payloads["giftCard"]["$object_payload"].update( - { - "cardNumber": "Test card number", - "cardPin": "Test card pin", +payloads["giftCard"]["$object_payload"].update({ + "cardNumber": + "Test card number", + "cardPin": + "Test card pin", "balance": { - "kind": "walletobjects#money", - "micros": 20000000, - "currencyCode": "USD", + "kind": "walletobjects#money", + "micros": 20000000, + "currencyCode": "USD", }, "balanceUpdateTime": { - "date": "2020-04-12T16:20:50.52Z", + "date": "2020-04-12T16:20:50.52Z", }, - "locations": [ - { + "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001, - } - ], - } -) + }], +}) ################# # Eventticket ################# -payloads["eventTicket"]["$class_payload"].update( - { +payloads["eventTicket"]["$class_payload"].update({ "eventName": { - "defaultValue": { - "language": "en-US", - "value": "Test event name", - }, - }, - "reviewStatus": "underReview", - } -) - -payloads["eventTicket"]["$object_payload"].update( - { - "state": "active", - "seatInfo": { - "kind": "walletobjects#eventSeat", - "seat": { - "kind": "walletobjects#localizedString", "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "42", + "language": "en-US", + "value": "Test event name", }, - }, - "row": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "G3", - }, - }, - "section": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "5", - }, - }, - "gate": { - "kind": "walletobjects#localizedString", - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "A", - }, - }, }, - "ticketHolderName": "Test ticket holder name", - "ticketNumber": "Test ticket number", - "locations": [ - { + "reviewStatus": "underReview", +}) + +payloads["eventTicket"]["$object_payload"].update({ + "state": + "active", + "seatInfo": { + "kind": "walletobjects#eventSeat", + "seat": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "42", + }, + }, + "row": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "G3", + }, + }, + "section": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "5", + }, + }, + "gate": { + "kind": "walletobjects#localizedString", + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "A", + }, + }, + }, + "ticketHolderName": + "Test ticket holder name", + "ticketNumber": + "Test ticket number", + "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001, - } - ], - } -) + }], +}) ################# # Flight ################# -payloads["flight"]["$class_payload"].update( - { +payloads["flight"]["$class_payload"].update({ "destination": { - "airportIataCode": "SFO", - "gate": "C3", - "terminal": "2", + "airportIataCode": "SFO", + "gate": "C3", + "terminal": "2", }, "flightHeader": { - "carrier": { - "carrierIataCode": "LX", - }, - "flightNumber": "123", + "carrier": { + "carrierIataCode": "LX", + }, + "flightNumber": "123", }, "origin": { - "airportIataCode": "LAX", - "gate": "A2", - "terminal": "1", + "airportIataCode": "LAX", + "gate": "A2", + "terminal": "1", }, "localScheduledDepartureDateTime": "2023-07-02T15:30:00", "reviewStatus": "underReview", - } -) +}) -payloads["flight"]["$object_payload"].update( - { - "state": "active", - "passengerName": "Test passenger name", +payloads["flight"]["$object_payload"].update({ + "state": + "active", + "passengerName": + "Test passenger name", "reservationInfo": { - "confirmationCode": "Test confirmation code", + "confirmationCode": "Test confirmation code", }, "boardingAndSeatingInfo": { - "seatNumber": "42", - "boardingGroup": "B", + "seatNumber": "42", + "boardingGroup": "B", }, - "locations": [ - { + "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001, - } - ], - } -) + }], +}) ################# # Transit ################# -payloads["transit"]["$class_payload"].update( - { +payloads["transit"]["$class_payload"].update({ "reviewStatus": "underReview", "transitType": "bus", "logo": { - "kind": "walletobjects#image", - "sourceUri": { - "kind": "walletobjects#uri", - "uri": "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png", - "description": "Test logo description", - }, + "kind": "walletobjects#image", + "sourceUri": { + "kind": + "walletobjects#uri", + "uri": + "https://live.staticflickr.com/65535/48690277162_cd05f03f4d_o.png", + "description": + "Test logo description", + }, }, - } -) +}) -payloads["transit"]["$object_payload"].update( - { - "passengerType": "singlePassenger", - "passengerNames": "Test passenger names", +payloads["transit"]["$object_payload"].update({ + "passengerType": + "singlePassenger", + "passengerNames": + "Test passenger names", "ticketLeg": { - "originStationCode": "LA", - "originName": { - "kind": "walletobjects#localizedString", - "translatedValues": [ - { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test translated origin name", - } - ], - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test default origin name", + "originStationCode": "LA", + "originName": { + "kind": "walletobjects#localizedString", + "translatedValues": [{ + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated origin name", + }], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default origin name", + }, }, - }, - "destinationStationCode": "SFO", - "destinationName": { - "kind": "walletobjects#localizedString", - "translatedValues": [ - { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test translated destination name", - } - ], - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test default destination name", + "destinationStationCode": "SFO", + "destinationName": { + "kind": "walletobjects#localizedString", + "translatedValues": [{ + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated destination name", + }], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default destination name", + }, }, - }, - "departureDateTime": "2020-04-12T16:20:50.52Z", - "arrivalDateTime": "2020-04-12T20:20:50.52Z", - "fareName": { - "kind": "walletobjects#localizedString", - "translatedValues": [ - { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test translated fare name", - } - ], - "defaultValue": { - "kind": "walletobjects#translatedString", - "language": "en-us", - "value": "Test default fare name", + "departureDateTime": "2020-04-12T16:20:50.52Z", + "arrivalDateTime": "2020-04-12T20:20:50.52Z", + "fareName": { + "kind": "walletobjects#localizedString", + "translatedValues": [{ + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test translated fare name", + }], + "defaultValue": { + "kind": "walletobjects#translatedString", + "language": "en-us", + "value": "Test default fare name", + }, }, - }, }, - "locations": [ - { + "locations": [{ "kind": "walletobjects#latLongPoint", "latitude": 37.424015499999996, "longitude": -122.09259560000001, - } - ], - } -) + }], +}) def indent(text, spaces): - """Enforce spacing/indentation on each new line""" - return text.replace("\n", "\n" + (" " * spaces)) + """Enforce spacing/indentation on each new line""" + return text.replace("\n", "\n" + (" " * spaces)) def format_payload_dotnet(unformatted_payload): - """Format JSON payloads for .NET syntax""" - formatted_output = [] + """Format JSON payloads for .NET syntax""" + formatted_output = [] - unformatted_payload = ( - unformatted_payload.replace(' "', " ") - .replace('": ', " = ") - .replace(" string = ", " @string = ") - .replace("]", "}") - ) + unformatted_payload = (unformatted_payload.replace(' "', " ").replace( + '": ', " = ").replace(" string = ", " @string = ").replace("]", "}")) - for line in unformatted_payload.split("\n"): - _indent = len(line) - len(line.lstrip(" ")) - if line.endswith("{"): - line = line[:-1] + f"new\n{' ' * _indent}{{" - if line.endswith("["): - line = line[:-1] + f"new object[]\n{' ' * _indent}{{" + for line in unformatted_payload.split("\n"): + _indent = len(line) - len(line.lstrip(" ")) + if line.endswith("{"): + line = line[:-1] + f"new\n{' ' * _indent}{{" + if line.endswith("["): + line = line[:-1] + f"new object[]\n{' ' * _indent}{{" - formatted_output.append(line) - return "\n".join(formatted_output) + formatted_output.append(line) + return "\n".join(formatted_output) + + +def format_batch_payload(unformatted_payload): + """Format batch request payloads with additional indentation.""" + formatted_payload = [unformatted_payload.split("\n")[0]] + formatted_payload += [" " + x for x in unformatted_payload.split("\n")[1:]] + return "\n".join(formatted_payload) lang_config = { - "java": { - "ext": "java", - "class_id": "%s.%s", - "object_id": "%s", - "formatter": lambda s: '\n "' - + s.replace('"', '\\"').replace("\n", '"\n + "') - + '"', - "filename": lambda s: f"src/main/java/Demo{s.title()}.java", - }, - "python": { - "ext": "py", - "class_id": 'f"{ISSUER_ID}.{CLASS_ID}"', - "object_id": "OBJECT_ID", - "filename": lambda s: f"demo_{s.lower()}.py", - }, - "nodejs": { - "ext": "js", - "class_id": "`${issuerId}.${classId}`", - "object_id": "objectId", - "formatter": lambda s: indent(s, 2), - "filename": lambda s: f"demo-{s.lower()}.js", - }, - "php": { - "ext": "php", - "class_id": '"{$issuerId}.{$classId}"', - "object_id": '"{$objectId}"', - "filename": lambda s: f"demo_{s.lower()}.php", - }, - "dotnet": { - "ext": "cs", - "class_id": '$"{issuerId}.{classId}"', - "object_id": "objectId", - "formatter": format_payload_dotnet, - "filename": lambda s: f"Demo{s.title()}.cs", - "indent": 2, - }, - "http": { - "ext": "http", - "class_id": "issuer-id.class-id", - "object_id": "issuer-id.user-id", - "filename": lambda s: f"demo_{s.lower()}.http", - }, + "java": { + "ext": + "java", + "class_id": + "%s.%s", + "object_id": + "%s", + "formatter": + lambda s: '\n "' + s.replace('"', '\\"').replace( + "\n", '"\n + "') + '"', + "filename": + lambda s: f"src/main/java/Demo{s[0].upper()}{s[1:]}.java", + "indent": + 2, + "continuation_indent": + 4, + "batch_set_statements": { + "generic": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setCardTitle(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage(\"en-US\").setValue(\"TITLE\")))", + " .setHeader(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage(\"en-US\").setValue(\"HEADER\")));", + ], + "offer": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setState(\"ACTIVE\");", + ], + "loyalty": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setState(\"ACTIVE\");", + ], + "giftCard": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setState(\"ACTIVE\")", + " .setCardNumber(\"CARD_NUMBER\");", + ], + "eventTicket": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setState(\"ACTIVE\");", + ], + "flight": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setState(\"ACTIVE\")", + " .setPassengerName(\"NAME\")", + " .setReservationInfo(new ReservationInfo());", + ], + "transit": [ + ".setId(objectId)", + " .setClassId(classId)", + " .setState(\"ACTIVE\")", + " .setTripType(\"ONE_WAY\");", + ] + }, + }, + "python": { + "ext": "py", + "class_id": 'f"{ISSUER_ID}.{CLASS_ID}"', + "object_id": "OBJECT_ID", + "indent": 4, + "continuation_indent": 4, + "filename": lambda s: f"demo_{s.lower()}.py", + "batch_set_statements": { + "generic": [], + "offer": [], + "loyalty": [], + "giftCard": [], + "eventTicket": [], + "flight": [], + "transit": [], + }, + }, + "nodejs": { + "ext": "js", + "class_id": "`${issuerId}.${classId}`", + "object_id": "objectId", + "indent": 2, + "continuation_indent": 4, + "formatter": lambda s: indent(s, 2), + "filename": lambda s: f"demo-{s.lower()}.js", + "batch_set_statements": { + "generic": [], + "offer": [], + "loyalty": [], + "giftCard": [], + "eventTicket": [], + "flight": [], + "transit": [], + }, + }, + "php": { + "ext": "php", + "class_id": '"{$issuerId}.{$classId}"', + "object_id": '"{$objectId}"', + "indent": 2, + "continuation_indent": 4, + "filename": lambda s: f"demo_{s.lower()}.php", + "batch_set_statements": { + "generic": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setCardTitle(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage(\"en-US\").setValue(\"TITLE\")));", + " $$object_typeObject->setHeader(new LocalizedString().setDefaultValue(new TranslatedString().setLanguage(\"en-US\").setValue(\"HEADER\")));", + ], + "offer": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setState(\"ACTIVE\");", + ], + "loyalty": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setState(\"ACTIVE\");", + ], + "giftCard": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setState(\"ACTIVE\");", + " $$object_typeObject->setCardNumber(\"CARD_NUMBER\");", + ], + "eventTicket": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setState(\"ACTIVE\");", + ], + "flight": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setState(\"ACTIVE\");", + " $$object_typeObject->setPassengerName(\"NAME\");", + " $$object_typeObject->setReservationInfo(new Google_Service_Walletobjects_ReservationInfo());", + ], + "transit": [ + "$$object_typeObject->setId($objectId);", + " $$object_typeObject->setClassId(\"$issuerId.$classId\");", + " $$object_typeObject->setState(\"ACTIVE\");", + " $$object_typeObject->setTripType(\"ONE_WAY\");", + ] + }, + }, + "dotnet": { + "ext": + "cs", + "class_id": + '$"{issuerId}.{classId}"', + "object_id": + "objectId", + "formatter": + format_payload_dotnet, + "filename": + lambda s: f"Demo{object_type[0].upper()}{object_type[1:]}.cs", + "indent": + 2, + "continuation_indent": + 4, + "batch_set_statements": { + "generic": [], + "offer": [], + "loyalty": [], + "giftCard": [], + "eventTicket": [], + "flight": [], + "transit": [], + }, + }, + "http": { + "ext": "http", + "class_id": "\"issuer-id.class-id\"", + "object_id": "\"issuer-id.user-id\"", + "filename": lambda s: f"demo_{s.lower()}.http", + "batch_set_statements": { + "generic": [], + "offer": [], + "loyalty": [], + "giftCard": [], + "eventTicket": [], + "flight": [], + "transit": [], + }, + }, } path = lambda *s: os.path.join(os.path.dirname(os.path.abspath(__file__)), *s) for lang, config in lang_config.items(): - with open(path(f"template.{config['ext']}"), "r", encoding="utf-8") as f: - template = f.read() - for object_type, content in payloads.items(): - output = template + # Get the language specific template file + with open(path(f"template.{config['ext']}"), "r", encoding="utf-8") as f: + template = f.read() - # JSON payloads - for name, value in content.items(): - payload = json.dumps(value, indent=config.get("indent", 2)) - if "formatter" in config: - payload = config["formatter"](payload) - output = output.replace(name, payload) + for object_type, content in payloads.items(): + output = template - # code placeholders - config["object_type"] = object_type - config["object_type_titlecase"] = object_type.title() - for name in ("object_type_titlecase", "object_type", "class_id", "object_id"): - output = output.replace(f'"${name}"', config[name]) - output = output.replace(f"${name}", config[name]) + # JSON payloads + for name, value in content.items(): + payload = json.dumps(value, indent=config.get("indent", 2)) + if "formatter" in config: + payload = config["formatter"](payload) + batch_payload = format_batch_payload(payload) + output = output.replace(f"{name}_batch", batch_payload) + output = output.replace(name, payload) - with open( - path("..", lang, config["filename"](object_type)), "w", encoding="utf-8" - ) as f: - f.write(output) + # code placeholders + config["object_type"] = object_type + config[ + "object_type_title"] = f"{object_type[0].upper()}{object_type[1:]}" + config["object_type_lower"] = object_type.lower() + config[ + "api_url"] = f"{BASE_URL}{url_map.get(object_type, '/generic/rest/v1/genericobject')}" + config["batch_statement"] = "\n".join( + config["batch_set_statements"][object_type]).replace( + "$object_type", object_type) + + for name in ("object_type_title", "object_type_lower", "object_type", + "class_id", "object_id", "api_url", "batch_statement"): + output = output.replace(f'"${name}"', config[name]) + output = output.replace(f"${name}", config[name]) + + with open(path("..", lang, config["filename"](object_type)), + "w", + encoding="utf-8") as f: + f.write(output) diff --git a/templates/template.cs b/templates/template.cs index 0c32bfd..2f9bbf3 100644 --- a/templates/template.cs +++ b/templates/template.cs @@ -25,35 +25,37 @@ using Microsoft.IdentityModel.Tokens; using Newtonsoft.Json; // [END imports] + /* - * keyFilePath - Path to service account key file from Google Cloud Console - * - Environment variable: GOOGLE_APPLICATION_CREDENTIALS - */ +* keyFilePath - Path to service account key file from Google Cloud Console +* - Environment variable: GOOGLE_APPLICATION_CREDENTIALS +*/ string keyFilePath = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS") ?? "/path/to/key.json"; /* - * issuerId - The issuer ID being used in this request - * - Environment variable: WALLET_ISSUER_ID - */ +* issuerId - The issuer ID being used in this request +* - Environment variable: WALLET_ISSUER_ID +*/ string issuerId = Environment.GetEnvironmentVariable("WALLET_ISSUER_ID") ?? "issuer-id"; /* - * classId - Developer-defined ID for the wallet class - * - Environment variable: WALLET_CLASS_ID - */ +* classId - Developer-defined ID for the wallet class +* - Environment variable: WALLET_CLASS_ID +*/ string classId = Environment.GetEnvironmentVariable("WALLET_CLASS_ID") ?? "test-$object_type-class-id"; /* - * userId - Developer-defined ID for the user, such as an email address - * - Environment variable: WALLET_USER_ID - */ +* userId - Developer-defined ID for the user, such as an email address +* - Environment variable: WALLET_USER_ID +*/ string userId = Environment.GetEnvironmentVariable("WALLET_USER_ID") ?? "user-id"; /* - * objectId - ID for the wallet object - * - Format: `issuerId.userId` - * - Should only include alphanumeric characters, '.', '_', or '-' - */ +* objectId - ID for the wallet object +* - Format: `issuerId.identifier` +* - Should only include alphanumeric characters, '.', '_', or '-' +* - `identifier` is developer-defined and unique to the user +*/ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; // [END setup] @@ -62,14 +64,14 @@ string objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Rep /////////////////////////////////////////////////////////////////////////////// // [START auth] -var credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) - .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) - .UnderlyingCredential; +ServiceAccountCredential credentials = (ServiceAccountCredential)GoogleCredential.FromFile(keyFilePath) + .CreateScoped(new[] { "https://www.googleapis.com/auth/wallet_object.issuer" }) + .UnderlyingCredential; -var httpClient = new HttpClient(); +HttpClient httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( - "Bearer", - await credentials.GetAccessTokenForRequestAsync() + "Bearer", + await credentials.GetAccessTokenForRequestAsync() ); // [END auth] @@ -83,7 +85,7 @@ var classPayload = $class_payload; HttpRequestMessage classRequest = new HttpRequestMessage(HttpMethod.Post, classUrl); classRequest.Content = new StringContent(JsonConvert.SerializeObject(classPayload)); -HttpResponseMessage classResponse = httpClient.Send(classRequest); ; +HttpResponseMessage classResponse = httpClient.Send(classRequest); string classContent = await classResponse.Content.ReadAsStringAsync(); @@ -139,6 +141,7 @@ SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgo JwtSecurityToken jwt = new JwtSecurityToken(new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); string saveUrl = $"https://pay.google.com/gp/v/save/{token}"; + Console.WriteLine(saveUrl); // [END jwt] @@ -202,3 +205,49 @@ HttpResponseMessage permissionsResponse = httpClient.Send(permissionsRequest); Console.WriteLine($"permissions PUT response: {await permissionsResponse.Content.ReadAsStringAsync()}"); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +// [START batch] +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch//example +string data = ""; + +// Example: Generate three new pass objects +for (int i = 0; i < 3; i++) +{ + // Generate a random user ID + userId = Regex.Replace(Guid.NewGuid().ToString(), "[^\\w.-]", "_"); + + // Generate an object ID with the user ID + objectId = $"{issuerId}.{new Regex(@"[^\w.-]", RegexOptions.Compiled).Replace(userId, "_")}-{classId}"; + var batchObject = $object_payload_batch; + + data += "--batch_createobjectbatch\n"; + data += "Content-Type: application/json\n\n"; + data += "POST /walletobjects/v1/$object_typeObject/\n\n"; + + data += JsonConvert.SerializeObject(batchObject) + "\n\n"; +} +data += "--batch_createobjectbatch--"; + +// Invoke the batch API calls +HttpRequestMessage objectRequest = new HttpRequestMessage( + HttpMethod.Post, + "https://walletobjects.googleapis.com/batch"); + +objectRequest.Content = new StringContent(data); +objectRequest.Content.Headers.ContentType = new MediaTypeHeaderValue("multipart/mixed"); +objectRequest.Content.Headers.ContentType.Parameters.Add( + // `boundary` is the delimiter between API calls in the batch request + new NameValueHeaderValue("boundary", "batch_createobjectbatch")); + +HttpResponseMessage objectResponse = httpClient.Send(objectRequest); + +string objectContent = await objectResponse.Content.ReadAsStringAsync(); + +Console.WriteLine($"object GET or POST response: {objectContent}"); +// [END batch] diff --git a/templates/template.java b/templates/template.java index 61171bb..1d7b745 100644 --- a/templates/template.java +++ b/templates/template.java @@ -18,7 +18,10 @@ // [START imports] import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; +import com.google.api.client.googleapis.batch.BatchRequest; +import com.google.api.client.googleapis.batch.json.JsonBatchCallback; import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.client.http.*; import com.google.api.client.http.json.JsonHttpContent; import com.google.api.client.json.GenericJson; @@ -32,9 +35,14 @@ import com.google.common.collect.Lists; import java.io.*; import java.security.interfaces.RSAPrivateKey; import java.util.*; + +// Only include if you are using the Google Wallet client library +// https://developers.google.com/wallet/retail/loyalty-cards/resources/libraries +import com.google.api.services.walletobjects.Walletobjects; +import com.google.api.services.walletobjects.model.*; // [END imports] -public class Demo$object_type_titlecase { +public class Demo$object_type_title { public static void main(String[] args) throws Exception { /* * keyFilePath - Path to service account key file from Google Cloud Console @@ -70,10 +78,12 @@ public class Demo$object_type_titlecase { /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - String objectId = String.format("%s.%s-%s", issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); + String objectId = String.format("%s.%s-%s", + issuerId, userId.replaceAll("[^\\w.-]", "_"), classId); // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -230,10 +240,71 @@ public class Demo$object_type_titlecase { HttpRequest permissionsRequest = httpRequestFactory.buildPutRequest( permissionsUrl, - new JsonHttpContent(new GsonFactory(), permissionsPayload)); + new JsonHttpContent(GsonFactory.getDefaultInstance(), permissionsPayload)); HttpResponse permissionsResponse = permissionsRequest.execute(); System.out.println("permissions PUT response: " + permissionsResponse.parseAsString()); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects + /////////////////////////////////////////////////////////////////////////////// + + // [START batch] + // Note: This example requires version 1.23 or higher of the + // `com.google.api-client` library. + // https://developers.google.com/api-client-library/java + try { + HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials); + + // Create the Wallet API client + Walletobjects client = new Walletobjects.Builder( + httpTransport, + GsonFactory.getDefaultInstance(), + requestInitializer) + .setApplicationName("APPLICATION_NAME") + .build(); + + // Create the batch request client + BatchRequest batch = client.batch(requestInitializer); + + // The callback will be invoked for each request in the batch + JsonBatchCallback<$object_type_titleObject> callback = new JsonBatchCallback<$object_type_titleObject>() { + // Invoked if the request was successful + public void onSuccess($object_type_titleObject response, HttpHeaders responseHeaders) { + System.out.println(response.toString()); + } + + // Invoked if the request failed + public void onFailure(GoogleJsonError e, HttpHeaders responseHeaders) { + System.out.println("Error Message: " + e.getMessage()); + } + }; + + // Example: Generate three new pass objects + for (int i = 0; i < 3; i++) { + // Generate a random user ID + userId = UUID.randomUUID() + .toString() + .replaceAll("[^\\w.-]", "_"); + + // Generate a random object ID with the user ID + objectId = String.format("%s.%s-%s", issuerId, userId, classId); + + $object_type_titleObject $object_typeObject = new $object_type_titleObject() + // See link below for more information on required properties + // $api_url + $batch_statement; + + client.$object_type_lowerobject().insert($object_typeObject).queue(batch, callback); + } + + // Invoke the batch API calls + batch.execute(); + } catch (Exception e) { + System.out.println("Error : " + e.getMessage()); + e.printStackTrace(); + } + // [END batch] } } diff --git a/templates/template.js b/templates/template.js index 0d0b6dc..35c380b 100644 --- a/templates/template.js +++ b/templates/template.js @@ -20,6 +20,7 @@ async function main() { // [START imports] const { GoogleAuth } = require('google-auth-library'); const jwt = require('jsonwebtoken'); + const { v4: uuidv4 } = require('uuid'); // [END imports] /* @@ -44,14 +45,15 @@ async function main() { * userId - Developer-defined ID for the user, such as an email address * - Environment variable: WALLET_USER_ID */ - const userId = process.env.WALLET_USER_ID || 'user-id'; + let userId = process.env.WALLET_USER_ID || 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ - const objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; + let objectId = `${issuerId}.${userId.replace(/[^\w.-]/g, '_')}-${classId}`; // [END setup] /////////////////////////////////////////////////////////////////////////////// @@ -91,8 +93,8 @@ async function main() { // [START object] const objectUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/$object_typeObject/'; const objectPayload = $object_payload; - let objectResponse; + try { objectResponse = await httpClient.request({ url: objectUrl + objectId, @@ -116,7 +118,7 @@ async function main() { // [END object] /////////////////////////////////////////////////////////////////////////////// - // Create a JWT for the object, and encode it to create a "Save" URL. + // Create a JWT for the object, and encode it to create a 'Save' URL. /////////////////////////////////////////////////////////////////////////////// // [START jwt] @@ -144,13 +146,13 @@ async function main() { // [START createIssuer] // New issuer name - const issuerName = "name"; + const issuerName = 'name'; // New issuer email address - const issuerEmail = "email-address"; + const issuerEmail = 'email-address'; // Issuer API endpoint - const issuerUrl = "https://walletobjects.googleapis.com/walletobjects/v1/issuer"; + const issuerUrl = 'https://walletobjects.googleapis.com/walletobjects/v1/issuer'; // New issuer information let issuerPayload = { @@ -183,8 +185,8 @@ async function main() { permissions: [ // Copy as needed for each email address that will need access { - emailAddress: "email-address", - role: "READER | WRITER | OWNER" + emailAddress: 'email-address', + role: 'READER | WRITER | OWNER' } ] }; @@ -197,4 +199,46 @@ async function main() { console.log('permissions PUT response:', permissionsResponse); // [END updatePermissions] + + /////////////////////////////////////////////////////////////////////////////// + // Batch create Google Wallet objects from an existing class + /////////////////////////////////////////////////////////////////////////////// + + //[START batch] + // The request body will be a multiline string + // See below for more information + // https://cloud.google.com/compute/docs/api/how-tos/batch#example + let data = ''; + let batchObject; + + // Example: Generate three new pass objects + for (let i = 0; i < 3; i++) { + // Generate a random user ID + userId = uuidv4().replace('[^\\w.-]', '_'); + + // Generate an object ID with the user ID + objectId = `${issuerId}.${userId}-${classId}`; + batchObject = $object_payload_batch; + + data += '--batch_createobjectbatch\n'; + data += 'Content-Type: application/json\n\n'; + data += 'POST /walletobjects/v1/$object_typeObject/\n\n'; + + data += JSON.stringify(batchObject) + '\n\n'; + } + data += '--batch_createobjectbatch--'; + + // Invoke the batch API calls + let batchResponse = await httpClient.request({ + url: 'https://walletobjects.googleapis.com/batch', + method: 'POST', + data: data, + headers: { + // `boundary` is the delimiter between API calls in the batch request + 'Content-Type': 'multipart/mixed; boundary=batch_createobjectbatch' + } + }); + + console.log('batch POST response:', batchResponse); + // [END batch] }; diff --git a/templates/template.php b/templates/template.php index bab4ade..888e98b 100644 --- a/templates/template.php +++ b/templates/template.php @@ -22,6 +22,7 @@ require __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; use Google\Auth\Credentials\ServiceAccountCredentials; use Google\Auth\Middleware\AuthTokenMiddleware; +use Google\Client as Google_Client; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Exception\ClientException; @@ -54,8 +55,9 @@ $userId = getenv('WALLET_USER_ID') ?: 'user-id'; /* * objectId - ID for the wallet object - * - Format: `issuerId.userId` + * - Format: `issuerId.identifier` * - Should only include alphanumeric characters, '.', '_', or '-' + * - `identifier` is developer-defined and unique to the user */ $objectId = "{$issuerId}." . preg_replace('/[^\w.-]/i', '_', $userId) . "-{$classId}"; // [END setup] @@ -209,3 +211,45 @@ $permissionsResponse = $httpClient->put( echo 'permissions PUT response: ' . $permissionsResponse->getBody(); // [END updatePermissions] + +/////////////////////////////////////////////////////////////////////////////// +// Batch create Google Wallet objects from an existing class +/////////////////////////////////////////////////////////////////////////////// + +//[START batch] +// Download the PHP client library from the following URL +// https://developers.google.com/wallet/generic/resources/libraries +require __DIR__ . '/lib/Walletobjects.php'; + +// The request body will be a multiline string +// See below for more information +// https://cloud.google.com/compute/docs/api/how-tos/batch#example +$client = new Google_Client(); +$client->setApplicationName("APPLICATION_NAME"); +$client->setScopes("https://www.googleapis.com/auth/wallet_object.issuer"); +$client->setAuthConfig($keyFilePath); +$client->setUseBatch(true); + +$service = new Google_Service_Walletobjects($client); + +$batch = $service->createBatch(); + +// Example: Generate three new pass objects +for ($i = 0; $i < 3; $i++) { + // Generate a random user ID + $userId = str_replace("[^\\w.-]", "_", uniqid()); + + // Generate a random object ID with the user ID + $objectId = "$issuerId.$userId-$classId"; + + $$object_typeObject = new Google_Service_Walletobjects_$object_type_titleObject(); + // See link below for more information on required properties + // $api_url + $batch_statement + + $batch->add($service->$object_type_lowerobject->insert($$object_typeObject)); +} +$results = $batch->execute(); + +print_r($results); +// [END batch] diff --git a/templates/template.py b/templates/template.py index 8fb7611..36549ca 100644 --- a/templates/template.py +++ b/templates/template.py @@ -17,8 +17,10 @@ # [START setup] # [START imports] +import json import os import re +import uuid from google.auth.transport.requests import AuthorizedSession from google.oauth2 import service_account @@ -43,8 +45,9 @@ CLASS_ID = os.environ.get("WALLET_CLASS_ID", "test-$object_type-class-id") USER_ID = os.environ.get("WALLET_USER_ID", "test@example.com") # objectId - ID for the wallet object -# - Format: `issuerId.userId` +# - Format: `issuerId.identifier` # - Should only include alphanumeric characters, '.', '_', or '-' +# - `identifier` is developer-defined and unique to the user OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [END setup] @@ -54,8 +57,8 @@ OBJECT_ID = "%s.%s-%s" % (ISSUER_ID, re.sub(r"[^\w.-]", "_", USER_ID), CLASS_ID) # [START auth] credentials = service_account.Credentials.from_service_account_file( - KEY_FILE_PATH, - scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) + KEY_FILE_PATH, + scopes=["https://www.googleapis.com/auth/wallet_object.issuer"]) http_client = AuthorizedSession(credentials) # [END auth] @@ -69,8 +72,8 @@ CLASS_URL = "https://walletobjects.googleapis.com/walletobjects/v1/$object_typeC class_payload = $class_payload class_response = http_client.post( - CLASS_URL, - json=class_payload + CLASS_URL, + json=class_payload ) print("class POST response: ", class_response.text) # [END class] @@ -85,12 +88,12 @@ object_payload = $object_payload object_response = http_client.get(OBJECT_URL + OBJECT_ID) if object_response.status_code == 404: - # Object does not yet exist - # Send POST request to create it - object_response = http_client.post( - OBJECT_URL, - json=object_payload - ) + # Object does not yet exist + # Send POST request to create it + object_response = http_client.post( + OBJECT_URL, + json=object_payload + ) print("object GET or POST response:", object_response.text) # [END object] @@ -101,17 +104,17 @@ print("object GET or POST response:", object_response.text) # [START jwt] claims = { - "iss": http_client.credentials.service_account_email, - "aud": "google", - "origins": ["www.example.com"], - "typ": "savetowallet", - "payload": { - "$object_typeObjects": [ - { - "id": OBJECT_ID - } - ] - } + "iss": http_client.credentials.service_account_email, + "aud": "google", + "origins": ["www.example.com"], + "typ": "savetowallet", + "payload": { + "$object_typeObjects": [ + { + "id": OBJECT_ID + } + ] + } } signer = crypt.RSASigner.from_service_account_file(KEY_FILE_PATH) @@ -137,16 +140,16 @@ ISSUER_URL = "https://walletobjects.googleapis.com/walletobjects/v1/issuer" # New issuer information issuer_payload = { - "name": ISSUER_NAME, - "contactInfo": { - "email": ISSUER_EMAIL - } + "name": ISSUER_NAME, + "contactInfo": { + "email": ISSUER_EMAIL + } } # Make the POST request issuer_response = http_client.post( - url=ISSUER_URL, - json=issuer_payload + url=ISSUER_URL, + json=issuer_payload ) print("issuer POST response:", issuer_response.text) @@ -162,20 +165,59 @@ permissions_url = f"https://walletobjects.googleapis.com/walletobjects/v1/permis # New issuer permissions information permissions_payload = { - "issuerId": ISSUER_ID, - "permissions": [ - # Copy as needed for each email address that will need access - { - "emailAddress": "email-address", - "role": "READER | WRITER | OWNER" - }, - ] + "issuerId": ISSUER_ID, + "permissions": [ + # Copy as needed for each email address that will need access + { + "emailAddress": "email-address", + "role": "READER | WRITER | OWNER" + }, + ] } permissions_response = http_client.put( - permissions_url, - json=permissions_payload + permissions_url, + json=permissions_payload ) print("permissions PUT response:", permissions_response.text) # [END updatePermissions] + +############################################################################### +# Batch create Google Wallet objects from an existing class +############################################################################### + +# [START batch] +# The request body will be a multiline string +# See below for more information +# https://cloud.google.com/compute/docs/api/how-tos/batch#example +data = "" + +# Example: Generate three new pass objects +for _ in range(3): + # Generate a random user ID + USER_ID = str(uuid.uuid4()).replace("[^\\w.-]", "_") + + # Generate an object ID with the user ID + OBJECT_ID = f"{ISSUER_ID}.{USER_ID}-{CLASS_ID}" + BATCH_OBJECT = $object_payload_batch + + data += "--batch_createobjectbatch\n" + data += "Content-Type: application/json\n\n" + data += "POST /walletobjects/v1/$object_typeObject/\n\n" + + data += json.dumps(BATCH_OBJECT) + "\n\n" + +data += "--batch_createobjectbatch--" + +# Invoke the batch API calls +response = http_client.post( + "https://walletobjects.googleapis.com/batch", + data=data, + headers={ + # `boundary` is the delimiter between API calls in the batch request + "Content-Type": "multipart/mixed; boundary=batch_createobjectbatch" + }) + +print(response.content.decode("UTF-8")) +# [END batch]