passgen: more pass generation
This commit is contained in:
parent
789e31e2d9
commit
c801d3db51
5 changed files with 178 additions and 4 deletions
|
@ -120,7 +120,7 @@ pub async fn insert_or_update_now_arc<T: Clone>(
|
|||
|
||||
pub async fn insert_or_update_many<T: Clone>(
|
||||
into: &dyn InsertOrUpdate<T>,
|
||||
values: Vec<T>,
|
||||
values: &Vec<T>,
|
||||
) -> Result<()> {
|
||||
let i = Arc::new(into);
|
||||
try_join_all(
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use chrono::Local;
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use futures_util::future::try_join_all;
|
||||
use google_walletobjects1::api::{FlightClass, FlightObject};
|
||||
use serde::Deserialize;
|
||||
use tokio::try_join;
|
||||
|
@ -47,6 +49,9 @@ enum Commands {
|
|||
/// Path to the image to read.
|
||||
image: PathBuf,
|
||||
},
|
||||
|
||||
/// generates a add-to-wallet URL for a set of passes.
|
||||
GenerateURL(GenerateURL),
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
|
@ -81,6 +86,11 @@ struct UploadScan {
|
|||
image: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
struct GenerateURL {
|
||||
pass_id: Vec<String>,
|
||||
}
|
||||
|
||||
async fn load_thing<'a, T: Deserialize<'a>>(path: &PathBuf) -> Result<T> {
|
||||
let data = tokio::fs::read(path).await?;
|
||||
let mut deser = serde_json::Deserializer::from_reader(data.as_slice());
|
||||
|
@ -95,7 +105,11 @@ async fn main() -> Result<()> {
|
|||
let command = cli.command.unwrap();
|
||||
|
||||
if let Commands::Scan { image } = &command {
|
||||
println!("{}", scan(image)?);
|
||||
let scanned = scan(image)?;
|
||||
println!("{}", scanned);
|
||||
let boarding_pass =
|
||||
BoardingPass::parse(scanned.as_bytes().to_vec(), &Local::now().date_naive())?;
|
||||
println!("{:#?}", boarding_pass);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
|
@ -183,10 +197,89 @@ async fn main() -> Result<()> {
|
|||
let (classes, passes) = passes_from_barcode(&cli.issuer_id, boarding_pass)?;
|
||||
|
||||
// Create all the classes.
|
||||
insert_or_update_many(&hub.flightclass(), classes).await?;
|
||||
insert_or_update_many(&hub.flightclass(), &classes).await?;
|
||||
|
||||
// Create all the objects.
|
||||
insert_or_update_many(&hub.flightobject(), passes).await?;
|
||||
insert_or_update_many(&hub.flightobject(), &passes).await?;
|
||||
|
||||
for pass in (&passes).iter() {
|
||||
println!("Generated pass: {}", pass.id.clone().unwrap());
|
||||
}
|
||||
|
||||
// Now generate the URL.
|
||||
println!(
|
||||
"{}",
|
||||
AddToWallet {
|
||||
service_account_email: sa.service_account_name.to_string(),
|
||||
|
||||
flight_classes: classes
|
||||
.iter()
|
||||
.map(|c| PassClassIdentifier {
|
||||
id: c.id.clone().unwrap(),
|
||||
})
|
||||
.collect(),
|
||||
flight_passes: passes
|
||||
.iter()
|
||||
.map(|p| PassIdentifier {
|
||||
id: p.id.clone().unwrap(),
|
||||
class_id: p.class_id.clone().unwrap(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
.to_url(&sa)?
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Commands::GenerateURL(generate_url) => {
|
||||
let pass_ids: Vec<String> = generate_url
|
||||
.pass_id
|
||||
.iter()
|
||||
.map(|pid| {
|
||||
if pid.contains('.') {
|
||||
pid.clone()
|
||||
} else {
|
||||
format!("{}.{}", cli.issuer_id, pid)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let passes_responses = try_join_all(
|
||||
pass_ids
|
||||
.iter()
|
||||
.map(|pid| hub.flightobject().get(&pid).doit()),
|
||||
)
|
||||
.await?;
|
||||
let passes: Vec<&FlightObject> = passes_responses
|
||||
.iter()
|
||||
.map(|result| {
|
||||
let (_, pass) = result;
|
||||
pass
|
||||
})
|
||||
.collect();
|
||||
|
||||
let class_ids: HashSet<String> =
|
||||
HashSet::from_iter(passes.iter().map(|p| p.class_id.clone().unwrap()));
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
AddToWallet {
|
||||
service_account_email: sa.service_account_name.to_string(),
|
||||
|
||||
flight_classes: class_ids
|
||||
.iter()
|
||||
.map(|c| PassClassIdentifier { id: c.clone() })
|
||||
.collect(),
|
||||
flight_passes: passes
|
||||
.iter()
|
||||
.map(|p| PassIdentifier {
|
||||
id: p.id.clone().unwrap(),
|
||||
class_id: p.class_id.clone().unwrap(),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
.to_url(&sa)?
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -117,6 +117,8 @@ impl CheckInSource {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct BoardingPass {
|
||||
pub initial_data: Vec<u8>,
|
||||
|
||||
pub passenger_name: String,
|
||||
pub eticket_indicator: char,
|
||||
|
||||
|
@ -226,6 +228,8 @@ impl BoardingPass {
|
|||
|
||||
// We now have enough to start composing the boardingpass.
|
||||
let mut boarding_pass = BoardingPass {
|
||||
initial_data: data.clone(),
|
||||
|
||||
passenger_name,
|
||||
eticket_indicator,
|
||||
|
||||
|
|
|
@ -34,4 +34,22 @@ pub static AIRLINE_DATA: phf::Map<&'static str, AirlineDefinition<'static>> = ph
|
|||
hero_image_logo_url: Some("https://p.lukegb.com/raw/FormerlyDistinctToad.png"),
|
||||
boarding_privilege_logo_url: Some("https://p.lukegb.com/raw/DefinitelyVerifiedTitmouse.png"),
|
||||
},
|
||||
"BA" => AirlineDefinition{
|
||||
iata_code: "BA",
|
||||
name: "British Airways",
|
||||
boarding_policy: "GROUP_BASED",
|
||||
seat_class_policy: "CLASS_BASED",
|
||||
|
||||
//boarding_pass_background_colour: "#b38f47", // BA Gold
|
||||
//alliance_logo_url: Some("https://p.lukegb.com/raw/UltimatelySunnyMacaque.png"),
|
||||
|
||||
boarding_pass_background_colour: "#ffffff", // BA no-status
|
||||
alliance_logo_url: Some("https://p.lukegb.com/raw/MultiplyAptHedgehog.png"),
|
||||
|
||||
frequent_flyer_program_name: Some("Executive Club Gold"),
|
||||
|
||||
logo_url: "https://p.lukegb.com/raw/HorriblyGreatTitmouse.png",
|
||||
hero_image_logo_url: None,
|
||||
boarding_privilege_logo_url: Some("https://p.lukegb.com/raw/VerticallyJustKoala.png"),
|
||||
},
|
||||
};
|
||||
|
|
|
@ -19,6 +19,12 @@ pub fn passes_from_barcode(
|
|||
)
|
||||
})?;
|
||||
|
||||
let frequent_flyer_program_data = if leg.frequent_flyer_airline.is_none() {
|
||||
None
|
||||
} else {
|
||||
AIRLINE_DATA.get(&leg.frequent_flyer_airline.as_ref().unwrap())
|
||||
};
|
||||
|
||||
let id_prefix = format!(
|
||||
"{}.{}{}-{}-{}{}",
|
||||
issuer_id,
|
||||
|
@ -63,9 +69,62 @@ pub fn passes_from_barcode(
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let pass_barcode = String::from_utf8(boarding_pass.initial_data)?;
|
||||
|
||||
let eticket_number =
|
||||
if leg.airline_numeric_code.is_some() && leg.document_serial_number.is_some() {
|
||||
Some(format!(
|
||||
"{}-{}",
|
||||
leg.airline_numeric_code.as_ref().unwrap(),
|
||||
leg.document_serial_number.as_ref().unwrap()
|
||||
))
|
||||
} else {
|
||||
Some("125-2150000000".to_string())
|
||||
};
|
||||
|
||||
let pass = FlightObject {
|
||||
id: Some(pass_id),
|
||||
class_id: Some(class_id.clone()),
|
||||
state: Some("ACTIVE".to_string()),
|
||||
|
||||
passenger_name: Some(boarding_pass.passenger_name.clone()),
|
||||
reservation_info: Some(ReservationInfo {
|
||||
confirmation_code: Some(leg.operating_carrier_pnr.clone()),
|
||||
eticket_number,
|
||||
frequent_flyer_info: if frequent_flyer_program_data.is_none() {
|
||||
None
|
||||
} else {
|
||||
Some(FrequentFlyerInfo {
|
||||
frequent_flyer_program_name: frequent_flyer_program_data
|
||||
.unwrap().frequent_flyer_program_name
|
||||
.map(|n| localized_string("en-GB", n)),
|
||||
frequent_flyer_number: leg.frequent_flyer_number.clone(),
|
||||
..Default::default()
|
||||
})
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
|
||||
boarding_and_seating_info: Some(BoardingAndSeatingInfo {
|
||||
boarding_group: Some("GROUP1".to_string()),
|
||||
seat_class: Some("Club World".to_string()),
|
||||
seat_number: Some(leg.seat_number.clone()),
|
||||
sequence_number: Some(leg.check_in_sequence.clone()),
|
||||
boarding_privilege_image: airline_data
|
||||
.boarding_privilege_logo_url
|
||||
.clone()
|
||||
.map(|u| url_to_image(u)),
|
||||
..Default::default()
|
||||
}),
|
||||
|
||||
barcode: Some(Barcode {
|
||||
type_: Some("aztec".to_string()),
|
||||
value: Some(pass_barcode),
|
||||
..Default::default()
|
||||
}),
|
||||
|
||||
hex_background_color: Some("#b38f47".to_string()),
|
||||
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue