summaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorjelemux <jeremias.weber@protonmail.com>2021-03-05 20:09:25 +0100
committerjelemux <jeremias.weber@protonmail.com>2021-03-05 20:09:25 +0100
commited19bef94a247d3eb501ae9f3bcd9496be229d80 (patch)
tree7762283853371daa8b73a8ece1ae54a37e10c4a0 /src/model
parent0b777005648985ec6d666efe7fb0094e870ee51e (diff)
downloadwasm-card-ed19bef94a247d3eb501ae9f3bcd9496be229d80.tar.gz
wasm-card-ed19bef94a247d3eb501ae9f3bcd9496be229d80.tar.bz2
get pdf generation to work and refactor code a little
Diffstat (limited to 'src/model')
-rw-r--r--src/model/vcard.rs325
1 files changed, 325 insertions, 0 deletions
diff --git a/src/model/vcard.rs b/src/model/vcard.rs
index 4670fe7..ea66224 100644
--- a/src/model/vcard.rs
+++ b/src/model/vcard.rs
@@ -1,9 +1,19 @@
+use vobject::vcard::VcardBuilder;
+use chrono::Local;
+use uuid::Uuid;
+use vobject::Vcard;
use crate::model::property_groups::address::Address;
use crate::model::property_groups::communication::Communication;
use crate::model::property_groups::name::Name;
use crate::model::property_groups::organizational::Organizational;
use crate::model::property_groups::other_identification::OtherIdentification;
use crate::model::property_groups::telephone::Telephone;
+use vobject::error::Result as VResult;
+use crate::model::VCardPropertyInputGroupObject;
+use boolinator::Boolinator;
+use vobject::parameters;
+use genpdf::Element as _;
+use genpdf::{elements, fonts, style};
/// Type that represents the data structure of a vcard.
#[derive(Clone, Debug)]
@@ -35,10 +45,325 @@ impl VCardData {
organizationals: Vec::new(),
}
}
+
make_vec_adder_fn!( fn add_name names => name: Name );
make_vec_adder_fn!( fn add_address addresses => address: Address );
make_vec_adder_fn!( fn add_telephone telephones => telephone: Telephone );
make_vec_adder_fn!( fn add_communication communications => communication: Communication );
make_vec_adder_fn!( fn add_other_identification other_identifications => other_identification: OtherIdentification );
make_vec_adder_fn!( fn add_organizational organizationals => organizational: Organizational );
+
+ pub fn build_vcard(&self) -> VResult<Vcard> {
+
+ let vcard_data = self.clone();
+ let mut builder = VcardBuilder::new();
+
+ for name in vcard_data.names {
+ if !name.is_empty() {
+ builder = builder.with_fullname(name.generate_fn()).with_name(
+ parameters!(),
+ (!name.last_name.is_empty()).as_some(name.last_name.clone()),
+ (!name.first_name.is_empty()).as_some(name.first_name.clone()),
+ (!name.middle_name.is_empty()).as_some(name.middle_name.clone()),
+ (!name.prefix.is_empty()).as_some(name.prefix.clone()),
+ (!name.suffix.is_empty()).as_some(name.suffix.clone()),
+ );
+ }
+ }
+
+ for address in vcard_data.addresses {
+ if !address.is_empty() {
+ let mut types = String::new();
+ if address.work {
+ types.push_str("WORK");
+ }
+ if address.home {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("HOME")
+ }
+
+ let params = if types.is_empty() {
+ parameters!()
+ } else {
+ parameters!("TYPE" => types)
+ };
+
+ builder = builder.with_adr(
+ params,
+ (!address.post_office_box.is_empty())
+ .as_some(address.post_office_box.clone()),
+ (!address.extension.is_empty()).as_some(address.extension.clone()),
+ (!address.street.is_empty()).as_some(address.street.clone()),
+ (!address.locality.is_empty()).as_some(address.locality.clone()),
+ (!address.region.is_empty()).as_some(address.region.clone()),
+ (!address.code.is_empty()).as_some(address.code.clone()),
+ (!address.country.is_empty()).as_some(address.country.clone()),
+ );
+ }
+ }
+
+ for telephone in vcard_data.telephones {
+ if !telephone.is_empty() {
+ let mut types = String::new();
+ if telephone.work {
+ types.push_str("WORK");
+ }
+ if telephone.home {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("HOME")
+ }
+ if telephone.text {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("TEXT")
+ }
+ if telephone.voice {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("VOICE")
+ }
+ if telephone.fax {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("FAX")
+ }
+ if telephone.cell {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("CELL")
+ }
+ if telephone.video {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("VIDEO")
+ }
+ if telephone.pager {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("PAGER")
+ }
+ if telephone.text_phone {
+ if !types.is_empty() {
+ types.push(',');
+ }
+ types.push_str("TEXTPHONE")
+ }
+
+ let params = if types.is_empty() {
+ parameters!()
+ } else {
+ parameters!("TYPE" => types)
+ };
+
+ builder = builder.with_tel(params, telephone.number.clone());
+ }
+ }
+
+ for communication in vcard_data.communications {
+ if !communication.email_address.is_empty() {
+ builder = builder.with_email(communication.email_address.clone());
+ }
+ if !communication.impp.is_empty() {
+ builder = builder.with_impp(communication.impp.clone());
+ }
+ }
+
+ for other_identification in vcard_data.other_identifications {
+ if !other_identification.nickname.is_empty() {
+ builder =
+ builder.with_nickname(parameters!(), other_identification.nickname);
+ }
+
+ match other_identification.photo {
+ Some(file) => builder = builder.with_photo(parameters!(), file.content),
+ None => (),
+ };
+
+ if !other_identification.anniversary.is_empty() {
+ builder = builder.with_anniversary(other_identification.anniversary);
+ }
+
+ if !other_identification.birthday.is_empty() {
+ builder = builder.with_bday(parameters!(), other_identification.birthday);
+ }
+
+ if !other_identification.gender.is_empty() {
+ builder = builder.with_gender(parameters!(), other_identification.gender);
+ }
+ }
+
+ for organizational in vcard_data.organizationals {
+ if !organizational.org.is_empty() {
+ builder = builder.with_org(vec![organizational.org]);
+ }
+
+ match organizational.logo {
+ Some(file) => builder = builder.with_logo(file.content),
+ None => (),
+ };
+
+ if !organizational.title.is_empty() {
+ builder = builder.with_title(organizational.title);
+ }
+
+ if !organizational.role.is_empty() {
+ builder = builder.with_role(organizational.role);
+ }
+
+ if !organizational.member.is_empty() {
+ builder = builder.with_member(organizational.member);
+ }
+
+ if !organizational.related.is_empty() {
+ builder = builder.with_related(organizational.related);
+ }
+ }
+
+ let uid = format!("urn:uuid:{}", Uuid::new_v4());
+
+ let rev = Local::now().to_string();
+
+ builder
+ .with_version("4.0".to_string())
+ .with_rev(rev)
+ .with_uid(uid)
+ .build()
+ }
+
+ pub fn generate_pdf(&self) -> Result<String, ()> {
+ let regular_bytes =
+ include_bytes!("/usr/share/fonts/liberation/LiberationSans-Regular.ttf");
+ let regular_font_data = fonts::FontData::new(
+ regular_bytes.to_vec(),
+ Some(printpdf::BuiltinFont::Helvetica),
+ )
+ .expect("font data should be correct");
+
+ let bold_bytes = include_bytes!("/usr/share/fonts/liberation/LiberationSans-Bold.ttf");
+ let bold_font_data = fonts::FontData::new(
+ bold_bytes.to_vec(),
+ Some(printpdf::BuiltinFont::HelveticaBold),
+ )
+ .expect("font data should be correct");
+
+ let italic_bytes = include_bytes!("/usr/share/fonts/liberation/LiberationSans-Italic.ttf");
+ let italic_font_data = fonts::FontData::new(
+ italic_bytes.to_vec(),
+ Some(printpdf::BuiltinFont::HelveticaOblique),
+ )
+ .expect("font data should be correct");
+
+ let bold_italic_bytes =
+ include_bytes!("/usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf");
+ let bold_italic_font_data = fonts::FontData::new(
+ bold_italic_bytes.to_vec(),
+ Some(printpdf::BuiltinFont::HelveticaBoldOblique),
+ )
+ .expect("font data should be correct");
+
+ let font_family = fonts::FontFamily {
+ regular: regular_font_data,
+ bold: bold_font_data,
+ italic: italic_font_data,
+ bold_italic: bold_italic_font_data,
+ };
+
+ let mut doc = genpdf::Document::new(font_family);
+
+ doc.set_title("wasm-card test");
+ doc.set_minimal_conformance();
+
+ let mut decorator = genpdf::SimplePageDecorator::new();
+ decorator.set_margins(10);
+ doc.set_page_decorator(decorator);
+
+ doc.set_line_spacing(1.25);
+
+ doc.push(
+ elements::Paragraph::new("genpdf Demo Document")
+ .aligned(elements::Alignment::Center)
+ .styled(style::Style::new().bold().with_font_size(20)),
+ );
+
+ let mut card_data = elements::Paragraph::new("");
+
+ let vcard_data = self.clone();
+
+ if let Some(name) = vcard_data.names.get(0) {
+ card_data.push_styled(
+ name.generate_fn(),
+ style::Effect::Bold
+ );
+ }
+ card_data.push(
+ ""
+ );
+ if let Some(communication) = vcard_data.communications.get(0) {
+ card_data.push(
+ communication.email_address.clone()
+ );
+ }
+ card_data.push(
+ ""
+ );
+ if let Some(address) = vcard_data.addresses.get(0) {
+ card_data.push(
+ address.street.clone()
+ );
+ card_data.push(
+ format!("{} {} {}", address.code, address.locality, address.extension)
+ );
+ card_data.push(
+ format!("{} {}", address.region, address.country)
+ );
+ }
+ card_data.push(
+ ""
+ );
+ for telephone in vcard_data.telephones {
+ card_data.push(
+ telephone.number
+ );
+ }
+
+ let framed_card_data = elements::FramedElement::new(
+ card_data
+ );
+
+ let mut table = elements::TableLayout::new(vec![1,1]);
+ table.set_cell_decorator(
+ elements::FrameCellDecorator::new(false, false, false)
+ );
+ for _i in 0..4 {
+ table
+ .row()
+ .element(framed_card_data.clone())
+ .element(framed_card_data.clone())
+ .push()
+ .expect("invalid table row");
+ }
+
+ doc.push(table);
+
+ // TODO fill doc with real data
+
+ let mut buf: Vec<u8> = Vec::new();
+ match doc.render(&mut buf) {
+ Ok(_) => Ok(match String::from_utf8(buf) {
+ Ok(s) => s,
+ Err(_) => return Err(()),
+ }),
+ Err(_) => Err(()),
+ }
+ }
}