diff --git a/examples/barcode.js b/examples/barcode.js new file mode 100644 index 0000000..7b9db75 --- /dev/null +++ b/examples/barcode.js @@ -0,0 +1,91 @@ +/** + * .barcode(), autocomplete and backward() methods example + * Here we set the barcode. To see all the results, you can + * both unzip .pkpass file or check the properties before + * generating the whole bundle + * + * Pass ?alt=true as querystring to test a barcode generate + * by a string + */ + +const app = require("./webserver"); +const { Pass } = require("../index"); + +app.all(function manageRequest(request, response) { + + let passName = request.params.modelName + "_" + (new Date()).toISOString().split('T')[0].replace(/-/ig, ""); + + let pass = new Pass({ + model: `./models/${request.params.modelName}`, + certificates: { + wwdr: "../certificates/WWDR.pem", + signerCert: "../certificates/passcertificate.pem", + signerKey: { + keyFile: "../certificates/passkey.pem", + passphrase: "123456" + } + }, + overrides: request.body || request.params || request.query, + }); + + let bc; + + if (request.query.alt === true) { + // After this, pass.props["barcodes"] will have support for all the formats + // while pass.props["barcode"] will be the first of barcodes. + + bc = pass.barcode("Thank you for using this package <3"); + } else { + // After this, pass.props["barcodes"] will have support for just two of three + // of the passed format (the valid ones) and pass.props["barcode"] the first of barcodes. + // if not specified, altText is automatically the message + + bc = pass.barcode([{ + message: "Thank you for using this package <3", + format: "PKBarcodeFormatCode128" + }, { + message: "Thank you for using this package <3", + format: "PKBarcodeFormatPDF417" + }, { + message: "Thank you for using this package <3", + format: "PKBarcodeFormatMock44617" + }]); + } + + // You can change the format chosen for barcode prop support by calling .backward() + // or cancel the support by calling empty .backward + // like bc.backward(). + // If the property passed does not exists, things does not change. + + bc.backward("PKBarcodeFormatPDF417"); + + // If your barcode structures got not autogenerated yet (as happens with string + // parameter of barcode) you can call .autocomplete() to generate the support + // to all the structures. Please beware that this will overwrite ONLY barcodes and not barcode. + + if (!request.query.alt) { + // String generated barcode returns autocomplete as empty function + bc.autocomplete(); + } + + console.log("Barcode property is now:", pass.props["barcode"]); + console.log("Barcodes support is autocompleted:", pass.props["barcodes"]); + + pass.generate().then(function(stream) { + response.set({ + "Content-type": "application/vnd.apple.pkpass", + "Content-disposition": `attachment; filename=${passName}.pkpass` + }); + + stream.pipe(response); + }).catch(err => { + + console.log(err); + + response.set({ + "Content-type": "text/html", + }); + + response.send(err.message); + }); +}); diff --git a/examples/expiration.js b/examples/expiration.js new file mode 100644 index 0000000..2ece981 --- /dev/null +++ b/examples/expiration.js @@ -0,0 +1,62 @@ +/** + * .void() and .expiration() methods example + * To check if a ticket is void, look at the barcode; + * If it is grayed, the ticket is voided. May not be showed on macOS. + * + * To check if a ticket has an expiration date, you'll + * have to wait two minutes. + */ + +const app = require("./webserver"); +const { Pass } = require("../index"); + +app.all(function manageRequest(request, response) { + if (!request.query.fn) { + response.send("Generate a voided pass.
Generate a pass with expiration date"); + return; + } + + let passName = request.params.modelName + "_" + (new Date()).toISOString().split('T')[0].replace(/-/ig, ""); + + let pass = new Pass({ + model: `./models/${request.params.modelName}`, + certificates: { + wwdr: "../certificates/WWDR.pem", + signerCert: "../certificates/passcertificate.pem", + signerKey: { + keyFile: "../certificates/passkey.pem", + passphrase: "123456" + } + }, + overrides: request.body || request.params || request.query, + }); + + if (request.query.fn === "void") { + pass.void(); + } else if (request.query.fn === "expiration") { + // 2 minutes later... + let d = new Date(); + d.setMinutes(d.getMinutes()+2); + + // setting the expiration + pass.expiration(d.toLocaleString()); + } + + pass.generate().then(function(stream) { + response.set({ + "Content-type": "application/vnd.apple.pkpass", + "Content-disposition": `attachment; filename=${passName}.pkpass` + }); + + stream.pipe(response); + }).catch(err => { + + console.log(err); + + response.set({ + "Content-type": "text/html", + }); + + response.send(err.message); + }); +}); diff --git a/examples/fields.js b/examples/fields.js new file mode 100644 index 0000000..d3e374b --- /dev/null +++ b/examples/fields.js @@ -0,0 +1,164 @@ +/** + * Fields pushing dimostration + * To see all the included Fields, just open the pass + * Refer to https://apple.co/2Nvshvn to see how passes + * have their fields disposed. + * + * In this example we are going to imitate an EasyJet boarding pass + * + * @Author: Alexander P. Cerutti + */ + +const app = require("./webserver"); +const { Pass } = require("../index"); + +app.all(function manageRequest(request, response) { + let passName = "exampleBooking" + "_" + (new Date()).toISOString().split('T')[0].replace(/-/ig, ""); + + let pass = new Pass({ + model: `./models/exampleBooking`, + certificates: { + wwdr: "../certificates/WWDR.pem", + signerCert: "../certificates/passcertificate.pem", + signerKey: { + keyFile: "../certificates/passkey.pem", + passphrase: "123456" + } + }, + overrides: request.body || request.params || request.query, + }); + + pass.transitType = "PKTransitTypeAir"; + + pass.headerFields.push({ + "key": "header1", + "label": "Data", + "value": "25 mag", + "textAlignment": "PKTextAlignmentCenter" + }, { + "key": "header2", + "label": "Volo", + "value": "EZY997", + "textAlignment": "PKTextAlignmentCenter" + }); + + pass.primaryFields.push({ + key: "IATA-source", + value: "NAP", + label: "Napoli", + textAlignment: "PKTextAlignmentLeft" + }, { + key: "IATA-destination", + value: "VCE", + label: "Venezia Marco Polo", + textAlignment: "PKTextAlignmentRight" + }); + + pass.secondaryFields.push({ + "key": "secondary1", + "label": "Imbarco chiuso", + "value": "18:40", + "textAlignment": "PKTextAlignmentCenter", + }, { + "key": "sec2", + "label": "Partenze", + "value": "19:10", + "textAlignment": "PKTextAlignmentCenter" + }, { + "key": "sec3", + "label": "SB", + "value": "Sì", + "textAlignment": "PKTextAlignmentCenter" + }, { + "key": "sec4", + "label": "Imbarco", + "value": "Anteriore", + "textAlignment": "PKTextAlignmentCenter" + }); + + pass.auxiliaryFields.push({ + "key": "aux1", + "label": "Passeggero", + "value": "MR. WHO KNOWS", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "aux2", + "label": "Posto", + "value": "1A*", + "textAlignment": "PKTextAlignmentCenter" + }); + + pass.backFields.push({ + "key": "document number", + "label": "Numero documento:", + "value": "- -", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "You're checked in, what next", + "label": "Hai effettuato il check-in, Quali sono le prospettive", + "value": "", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "Check In", + "label": "1. check-in✓", + "value": "", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "checkIn", + "label": "", + "value": "Le uscite d'imbarco chiudono 30 minuti prima della partenza, quindi sii puntuale. In questo aeroporto puoi utilizzare la corsia Fast Track ai varchi di sicurezza.", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "2. Bags", + "label": "2. Bagaglio", + "value": "", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "Require special assistance", + "label": "Assistenza speciale", + "value": "Se hai richiesto assistenza speciale, presentati a un membro del personale nell'area di Consegna bagagli almeno 90 minuti prima del volo.", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "3. Departures", + "label": "3. Partenze", + "value": "", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "photoId", + "label": "Un documento d’identità corredato di fotografia", + "value": "è obbligatorio su TUTTI i voli. Per un viaggio internazionale è necessario un passaporto valido o, dove consentita, una carta d’identità.", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "yourSeat", + "label": "Il tuo posto:", + "value": "verifica il tuo numero di posto nella parte superiore. Durante l’imbarco utilizza le scale anteriori e posteriori: per le file 1-10 imbarcati dalla parte anteriore; per le file 11-31 imbarcati dalla parte posteriore. Colloca le borse di dimensioni ridotte sotto il sedile davanti a te.", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "Pack safely", + "label": "Bagaglio sicuro", + "value": "Fai clic http://easyjet.com/it/articoli-pericolosi per maggiori informazioni sulle merci pericolose oppure visita il sito CAA http://www.caa.co.uk/default.aspx?catid=2200", + "textAlignment": "PKTextAlignmentLeft" + }, { + "key": "Thank you for travelling easyJet", + "label": "Grazie per aver viaggiato con easyJet", + "value": "", + "textAlignment": "PKTextAlignmentLeft" + }); + + pass.generate().then(function(stream) { + response.set({ + "Content-type": "application/vnd.apple.pkpass", + "Content-disposition": `attachment; filename=${passName}.pkpass` + }); + + stream.pipe(response); + }).catch(err => { + console.log(err); + + response.set({ + "Content-type": "text/html" + }); + + response.send(err.message); + }); +}); diff --git a/examples/localization.js b/examples/localization.js new file mode 100644 index 0000000..488e43b --- /dev/null +++ b/examples/localization.js @@ -0,0 +1,73 @@ +/** + * .localize() methods example + * To see all the included languages, you have to unzip the + * .pkpass file and check for .lproj folders + */ + +const app = require("./webserver"); +const { Pass } = require("../index"); + +app.all(function manageRequest(request, response) { + + let passName = request.params.modelName + "_" + (new Date()).toISOString().split('T')[0].replace(/-/ig, ""); + + let pass = new Pass({ + model: `./models/${request.params.modelName}`, + certificates: { + wwdr: "../certificates/WWDR.pem", + signerCert: "../certificates/passcertificate.pem", + signerKey: { + keyFile: "../certificates/passkey.pem", + passphrase: "123456" + } + }, + overrides: request.body || request.params || request.query, + }); + + // For each language you include, an .lproj folder in pass bundle + // is created or included. You may not want to add translations but + // only images for a specific language. So you create manually + // an .lproj folder in your pass model then add the language here below. + // If no translations were added, the folder + // is included or created but without pass.strings file + + // English, does not has an .lproj folder and no translation + // Text placeholders may not be showed for the english language + // (e.g. "Event" and "Location" as literal) and another language may be used instead + pass.localize("en"); + + // Italian, already has an .lproj which gets included + pass.localize("it", { + "EVENT": "Evento", + "LOCATION": "Dove" + }); + + // German, doesn't, so is created + pass.localize("de", { + "EVENT": "Ereignis", + "LOCATION": "Ort" + }); + + // This language does not exist but is still added as .lproj folder + pass.localize("zu", {}); + + console.log("Added languages", Object.keys(pass.l10n).join(", ")) + + pass.generate().then(function(stream) { + response.set({ + "Content-type": "application/vnd.apple.pkpass", + "Content-disposition": `attachment; filename=${passName}.pkpass` + }); + + stream.pipe(response); + }).catch(err => { + + console.log(err); + + response.set({ + "Content-type": "text/html", + }); + + response.send(err.message); + }); +}); diff --git a/examples/models/exampleBooking.pass/footer.png b/examples/models/exampleBooking.pass/footer.png new file mode 100755 index 0000000..a7b8abb Binary files /dev/null and b/examples/models/exampleBooking.pass/footer.png differ diff --git a/examples/models/exampleBooking.pass/footer@2x.png b/examples/models/exampleBooking.pass/footer@2x.png new file mode 100755 index 0000000..de04b11 Binary files /dev/null and b/examples/models/exampleBooking.pass/footer@2x.png differ diff --git a/examples/models/exampleBooking.pass/icon.png b/examples/models/exampleBooking.pass/icon.png new file mode 100755 index 0000000..bf916b1 Binary files /dev/null and b/examples/models/exampleBooking.pass/icon.png differ diff --git a/examples/models/exampleBooking.pass/icon@2x.png b/examples/models/exampleBooking.pass/icon@2x.png new file mode 100755 index 0000000..6a800d3 Binary files /dev/null and b/examples/models/exampleBooking.pass/icon@2x.png differ diff --git a/examples/models/exampleBooking.pass/logo.png b/examples/models/exampleBooking.pass/logo.png new file mode 100755 index 0000000..a7758da Binary files /dev/null and b/examples/models/exampleBooking.pass/logo.png differ diff --git a/examples/models/exampleBooking.pass/logo@2x.png b/examples/models/exampleBooking.pass/logo@2x.png new file mode 100755 index 0000000..ef70f4f Binary files /dev/null and b/examples/models/exampleBooking.pass/logo@2x.png differ diff --git a/examples/models/exampleBooking.pass/pass.json b/examples/models/exampleBooking.pass/pass.json new file mode 100644 index 0000000..f1fccb0 --- /dev/null +++ b/examples/models/exampleBooking.pass/pass.json @@ -0,0 +1,34 @@ +{ + "formatVersion": 1, + "passTypeIdentifier": "pass.com.example.myapp", + "serialNumber": "nmyuxofgna", + "teamIdentifier": "F53WB8AE67", + "webServiceURL": "https://192.168.1.254:80/", + "authenticationToken": "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc", + "relevantDate": "2011-12-08T13:00-08:00", + "locations": [ + { + "longitude": -122.3748889, + "latitude": 37.6189722 + }, + { + "longitude": -122.03118, + "latitude": 37.33182 + } + ], + "barcodes": [{ + "message": "123456789", + "format": "PKBarcodeFormatQR", + "messageEncoding": "iso-8859-1" + }], + "barcode": { + "message": "123456789", + "format": "PKBarcodeFormatQR", + "messageEncoding": "iso-8859-1" + }, + "organizationName": "Apple Inc.", + "description": "A Booking pass", + "foregroundColor": "rgb(255, 255, 255)", + "backgroundColor": "rgb(253, 123, 35)", + "boardingPass": {} +} diff --git a/examples/models/examplePass.pass/background.png b/examples/models/examplePass.pass/background.png new file mode 100644 index 0000000..da653a8 Binary files /dev/null and b/examples/models/examplePass.pass/background.png differ diff --git a/examples/models/examplePass.pass/background@2x.png b/examples/models/examplePass.pass/background@2x.png new file mode 100644 index 0000000..dea4491 Binary files /dev/null and b/examples/models/examplePass.pass/background@2x.png differ diff --git a/examples/models/examplePass.pass/icon.png b/examples/models/examplePass.pass/icon.png new file mode 100644 index 0000000..a7b90c9 Binary files /dev/null and b/examples/models/examplePass.pass/icon.png differ diff --git a/examples/models/examplePass.pass/icon@2x.png b/examples/models/examplePass.pass/icon@2x.png new file mode 100644 index 0000000..9f44f21 Binary files /dev/null and b/examples/models/examplePass.pass/icon@2x.png differ diff --git a/examples/models/examplePass.pass/it.lproj/icon.png b/examples/models/examplePass.pass/it.lproj/icon.png new file mode 100644 index 0000000..a7b90c9 Binary files /dev/null and b/examples/models/examplePass.pass/it.lproj/icon.png differ diff --git a/examples/models/examplePass.pass/it.lproj/icon@2x.png b/examples/models/examplePass.pass/it.lproj/icon@2x.png new file mode 100644 index 0000000..9f44f21 Binary files /dev/null and b/examples/models/examplePass.pass/it.lproj/icon@2x.png differ diff --git a/examples/models/examplePass.pass/it.lproj/thumbnail.png b/examples/models/examplePass.pass/it.lproj/thumbnail.png new file mode 100644 index 0000000..da653a8 Binary files /dev/null and b/examples/models/examplePass.pass/it.lproj/thumbnail.png differ diff --git a/examples/models/examplePass.pass/it.lproj/thumbnail@2x.png b/examples/models/examplePass.pass/it.lproj/thumbnail@2x.png new file mode 100644 index 0000000..dea4491 Binary files /dev/null and b/examples/models/examplePass.pass/it.lproj/thumbnail@2x.png differ diff --git a/examples/models/examplePass.pass/logo.png b/examples/models/examplePass.pass/logo.png new file mode 100644 index 0000000..9c44743 Binary files /dev/null and b/examples/models/examplePass.pass/logo.png differ diff --git a/examples/models/examplePass.pass/logo@2x.png b/examples/models/examplePass.pass/logo@2x.png new file mode 100644 index 0000000..5efaa73 Binary files /dev/null and b/examples/models/examplePass.pass/logo@2x.png differ diff --git a/examples/models/examplePass.pass/pass.json b/examples/models/examplePass.pass/pass.json new file mode 100644 index 0000000..673f4fb --- /dev/null +++ b/examples/models/examplePass.pass/pass.json @@ -0,0 +1,49 @@ +{ + "formatVersion": 1, + "passTypeIdentifier": "pass.com.example.myapp", + "serialNumber": "nmyuxofgna", + "teamIdentifier": "F53WB8AE67", + "webServiceURL": "https://192.168.1.254:80/", + "authenticationToken": "vxwxd7J8AlNNFPS8k0a0FfUFtq0ewzFdc", + "relevantDate": "2011-12-08T13:00-08:00", + "locations": [ + { + "longitude": -122.3748889, + "latitude": 37.6189722 + }, + { + "longitude": -122.03118, + "latitude": 37.33182 + } + ], + "barcodes": [{ + "message": "123456789", + "format": "PKBarcodeFormatQR", + "messageEncoding": "iso-8859-1" + }], + "barcode": { + "message": "123456789", + "format": "PKBarcodeFormatQR", + "messageEncoding": "iso-8859-1" + }, + "organizationName": "Apple Inc.", + "description": "Apple Event Ticket", + "foregroundColor": "rgb(255, 255, 255)", + "backgroundColor": "rgb(60, 65, 76)", + "eventTicket": { + "primaryFields": [ + { + "key": "event", + "label": "EVENT", + "value": "The Beat Goes On" + } + ], + "secondaryFields": [ + { + "key": "loc", + "label": "LOCATION", + "value": "Moscone West" + } + ] + } +} diff --git a/examples/models/examplePass.pass/thumbnail.png b/examples/models/examplePass.pass/thumbnail.png new file mode 100644 index 0000000..da653a8 Binary files /dev/null and b/examples/models/examplePass.pass/thumbnail.png differ diff --git a/examples/models/examplePass.pass/thumbnail@2x.png b/examples/models/examplePass.pass/thumbnail@2x.png new file mode 100644 index 0000000..dea4491 Binary files /dev/null and b/examples/models/examplePass.pass/thumbnail@2x.png differ diff --git a/examples/webserver.js b/examples/webserver.js new file mode 100644 index 0000000..07b6dc4 --- /dev/null +++ b/examples/webserver.js @@ -0,0 +1,25 @@ +/* + * Generic webserver instance for the examples + * @Author Alexander P. Cerutti + */ + +const express = require("express"); +const app = express(); + +app.use(express.json()); + +app.listen(8080, "0.0.0.0", function(request, response) { + console.log("Webserver started."); +}); + +app.all("/", function (request, response) { + response.redirect("/gen/"); +}); + +app.route("/gen") + .all((req, res) => { + res.set("Content-Type", "text/html"); + res.send("Cannot generate a pass. Specify a modelName in the url to continue.
Usage: /gen/modelName") + }); + +module.exports = app.route("/gen/:modelName");