summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2018-04-25 14:59:37 +0200
committerGitHub <noreply@github.com>2018-04-25 14:59:37 +0200
commit2b10ab0b3627ea73cf4101112c035a81e2f1bd37 (patch)
treee64348e5795d4c3fbcba0f8e70453688b22c2e57
parent5457834ea13438be937a76b62e5d881d15f195af (diff)
parentd6f8751f6e8cdb25dfffd5c6ca2b247902b97d41 (diff)
downloadimag-2b10ab0b3627ea73cf4101112c035a81e2f1bd37.zip
imag-2b10ab0b3627ea73cf4101112c035a81e2f1bd37.tar.gz
Merge pull request #1450 from matthiasbeyer/libimagcontact/not-based-on-libimagentryref
libimagcontact: not based on libimagentryref
-rw-r--r--bin/domain/imag-contact/Cargo.toml7
-rw-r--r--bin/domain/imag-contact/src/create.rs6
-rw-r--r--bin/domain/imag-contact/src/main.rs124
-rw-r--r--bin/domain/imag-contact/src/util.rs139
-rw-r--r--lib/domain/libimagcontact/Cargo.toml16
-rw-r--r--lib/domain/libimagcontact/src/contact.rs51
-rw-r--r--lib/domain/libimagcontact/src/deser.rs162
-rw-r--r--lib/domain/libimagcontact/src/error.rs12
-rw-r--r--lib/domain/libimagcontact/src/iter.rs7
-rw-r--r--lib/domain/libimagcontact/src/lib.rs16
-rw-r--r--lib/domain/libimagcontact/src/store.rs112
-rw-r--r--lib/domain/libimagcontact/src/util.rs8
12 files changed, 349 insertions, 311 deletions
diff --git a/bin/domain/imag-contact/Cargo.toml b/bin/domain/imag-contact/Cargo.toml
index 5986b77..eec3521 100644
--- a/bin/domain/imag-contact/Cargo.toml
+++ b/bin/domain/imag-contact/Cargo.toml
@@ -38,12 +38,7 @@ libimagutil = { version = "0.8.0", path = "../../../lib/etc/libimagutil"
libimagentryref = { version = "0.8.0", path = "../../../lib/entry/libimagentryref" }
libimagentryedit = { version = "0.8.0", path = "../../../lib/entry/libimagentryedit" }
libimaginteraction = { version = "0.8.0", path = "../../../lib/etc/libimaginteraction" }
-
-[dependencies.libimagcontact]
-version = "0.8.0"
-path = "../../../lib/domain/libimagcontact"
-default-features = false
-features = ["deser"]
+libimagcontact = { version = "0.8.0", path = "../../../lib/domain/libimagcontact" }
[dependencies.clap]
version = "^2.29"
diff --git a/bin/domain/imag-contact/src/create.rs b/bin/domain/imag-contact/src/create.rs
index 15d885b..a9573c1 100644
--- a/bin/domain/imag-contact/src/create.rs
+++ b/bin/domain/imag-contact/src/create.rs
@@ -44,14 +44,13 @@ use toml_query::read::TomlValueReadExt;
use toml::Value;
use uuid::Uuid;
+use libimagcontact::store::ContactStore;
use libimagcontact::error::ContactError as CE;
-use libimagcontact::store::UniqueContactPathGenerator;
use libimagrt::runtime::Runtime;
use libimagerror::str::ErrFromStr;
use libimagerror::trace::MapErrTrace;
use libimagerror::trace::trace_error;
use libimagutil::warn_result::WarnResult;
-use libimagentryref::refstore::RefStore;
const TEMPLATE : &'static str = include_str!("../static/new-contact-template.toml");
@@ -158,7 +157,8 @@ pub fn create(rt: &Runtime) {
if let Some(location) = location {
if !scmd.is_present("dont-track") {
- RefStore::create_ref::<UniqueContactPathGenerator, _>(rt.store(), location)
+ rt.store()
+ .create_from_path(&location)
.map_err_trace_exit_unwrap(1);
info!("Created entry in store");
diff --git a/bin/domain/imag-contact/src/main.rs b/bin/domain/imag-contact/src/main.rs
index 031c216..86c9845 100644
--- a/bin/domain/imag-contact/src/main.rs
+++ b/bin/domain/imag-contact/src/main.rs
@@ -48,7 +48,6 @@ extern crate libimagstore;
extern crate libimagerror;
extern crate libimagutil;
extern crate libimaginteraction;
-extern crate libimagentryref;
extern crate libimagentryedit;
use std::process::exit;
@@ -57,7 +56,6 @@ use std::io::Write;
use handlebars::Handlebars;
use clap::ArgMatches;
-use vobject::vcard::Vcard;
use toml_query::read::TomlValueReadTypeExt;
use walkdir::WalkDir;
@@ -67,14 +65,12 @@ use libimagerror::str::ErrFromStr;
use libimagerror::trace::MapErrTrace;
use libimagerror::io::ToExitCode;
use libimagerror::exit::ExitUnwrap;
+use libimagerror::iter::TraceIterator;
use libimagcontact::store::ContactStore;
-use libimagcontact::store::UniqueContactPathGenerator;
use libimagcontact::error::ContactError as CE;
use libimagcontact::contact::Contact;
use libimagcontact::deser::DeserVcard;
use libimagstore::iter::get::StoreIdGetIteratorExtension;
-use libimagentryref::reference::Ref;
-use libimagentryref::refstore::RefStore;
mod ui;
mod util;
@@ -128,24 +124,13 @@ fn list(rt: &Runtime) {
.ok_or_else(|| CE::from("StoreId not found".to_owned()))
.map_err_trace_exit_unwrap(1);
- fle
- .get_contact_data()
- .map(|cd| (fle, cd))
- .map(|(fle, cd)| (fle, cd.into_inner()))
- .map(|(fle, cd)| {
- let card = Vcard::from_component(cd).unwrap_or_else(|e| {
- error!("Element is not a VCARD object: {:?}", e);
- exit(1)
- });
- (fle, card)
- })
- .map_err_trace_exit_unwrap(1)
+ fle.deser().map_err_trace_exit_unwrap(1)
})
.enumerate();
if scmd.is_present("json") {
- let v : Vec<DeserVcard> = iterator
- .map(|(_, (_, vcard))| DeserVcard::from(vcard)).collect();
+ let v : Vec<DeserVcard> = iterator.map(|tpl| tpl.1).collect();
+
match ::serde_json::to_string(&v) {
Ok(s) => writeln!(rt.stdout(), "{}", s).to_exit_code().unwrap_or_exit(),
Err(e) => {
@@ -155,9 +140,8 @@ fn list(rt: &Runtime) {
}
} else {
iterator
- .map(|(i, (fle, vcard))| {
- let hash = String::from(fle.get_hash().map_err_trace_exit_unwrap(1));
- let data = build_data_object_for_handlebars(i, hash, &vcard);
+ .map(|(i, deservcard)| {
+ let data = build_data_object_for_handlebars(i, &deservcard);
list_format.render("format", &data)
.err_from_str()
@@ -217,32 +201,47 @@ fn import(rt: &Runtime) {
}
fn show(rt: &Runtime) {
- let scmd = rt.cli().subcommand_matches("show").unwrap();
- let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap
+ let scmd = rt.cli().subcommand_matches("show").unwrap();
+ let hash = scmd.value_of("hash").map(String::from).unwrap(); // safed by clap
+ let show_format = get_contact_print_format("contact.show_format", rt, &scmd);
+ let out = rt.stdout();
+ let mut outlock = out.lock();
- let contact_data = rt.store()
- .get_ref::<UniqueContactPathGenerator, _>(hash.clone())
- .map_err_trace_exit_unwrap(1)
- .ok_or(CE::from(format!("No entry for hash {}", hash)))
- .map_err_trace_exit_unwrap(1)
- .get_contact_data()
+ rt.store()
+ .all_contacts()
.map_err_trace_exit_unwrap(1)
- .into_inner();
- let vcard = Vcard::from_component(contact_data)
- .unwrap_or_else(|e| {
- error!("Element is not a VCARD object: {:?}", e);
+ .into_get_iter(rt.store())
+ .trace_unwrap_exit(1)
+ .map(|o| o.unwrap_or_else(|| {
+ error!("Failed to get entry");
exit(1)
- });
+ }))
+ .filter_map(|entry| {
+ let deser = entry.deser().map_err_trace_exit_unwrap(1);
- let show_format = get_contact_print_format("contact.show_format", rt, &scmd);
- let data = build_data_object_for_handlebars(0, hash, &vcard);
+ if deser.uid()
+ .ok_or_else(|| {
+ error!("Could not get StoreId from Store::all_contacts(). This is a BUG!");
+ ::std::process::exit(1)
+ })
+ .unwrap() // exited above
+ .starts_with(&hash)
+ {
+ Some(deser)
+ } else {
+ None
+ }
+ })
+ .for_each(|elem| {
+ let data = build_data_object_for_handlebars(0, &elem);
- let s = show_format
- .render("format", &data)
- .err_from_str()
- .map_err(CE::from)
- .map_err_trace_exit_unwrap(1);
- let _ = writeln!(::std::io::stdout(), "{}", s).to_exit_code().unwrap_or_exit();
+ let s = show_format
+ .render("format", &data)
+ .err_from_str()
+ .map_err(CE::from)
+ .map_err_trace_exit_unwrap(1);
+ let _ = writeln!(outlock, "{}", s).to_exit_code().unwrap_or_exit();
+ });
}
fn find(rt: &Runtime) {
@@ -270,30 +269,20 @@ fn find(rt: &Runtime) {
})
.unwrap() // safed above
})
- .filter_map(|cont| {
- let comp = cont
- .get_contact_data()
- .map_err_trace_exit_unwrap(1)
- .into_inner();
-
- let card = Vcard::from_component(comp)
- .map_err(|_| {
- error!("Could not build Vcard from {:?}", cont.get_location());
- ::std::process::exit(1)
- })
- .unwrap(); // safed above
+ .filter_map(|entry| {
+ let card = entry.deser().map_err_trace_exit_unwrap(1);
let str_contains_any = |s: &String, v: &Vec<String>| {
v.iter().any(|i| s.contains(i))
};
- let take = card.adr().iter().any(|a| str_contains_any(a.raw(), &grepstring))
- || card.email().iter().any(|a| str_contains_any(a.raw(), &grepstring))
- || card.fullname().iter().any(|a| str_contains_any(a.raw(), &grepstring));
+ let take = card.adr().iter().any(|a| str_contains_any(a, &grepstring))
+ || card.email().iter().any(|a| str_contains_any(a, &grepstring))
+ || card.fullname().iter().any(|a| str_contains_any(a, &grepstring));
if take {
// optimization so we don't have to parse again in the next step
- Some((cont, card))
+ Some((entry, card))
} else {
None
}
@@ -301,8 +290,8 @@ fn find(rt: &Runtime) {
.enumerate();
if scmd.is_present("json") {
- let v : Vec<DeserVcard> = iterator
- .map(|(_, (_, vcard))| DeserVcard::from(vcard)).collect();
+ let v : Vec<DeserVcard> = iterator.map(|(_, tlp)| tlp.1).collect();
+
match ::serde_json::to_string(&v) {
Ok(s) => writeln!(rt.stdout(), "{}", s).to_exit_code().unwrap_or_exit(),
Err(e) => {
@@ -312,22 +301,22 @@ fn find(rt: &Runtime) {
}
} else if scmd.is_present("find-id") {
iterator
- .for_each(|(_i, (fle, _card))| {
- writeln!(rt.stdout(), "{}", fle.get_location())
+ .for_each(|(_i, (entry, _))| {
+ writeln!(rt.stdout(), "{}", entry.get_location())
.to_exit_code()
.unwrap_or_exit();
})
} else if scmd.is_present("find-full-id") {
let storepath = rt.store().path().display();
iterator
- .for_each(|(_i, (fle, _card))| {
- writeln!(rt.stdout(), "{}/{}", storepath, fle.get_location())
+ .for_each(|(_i, (entry, _))| {
+ writeln!(rt.stdout(), "{}/{}", storepath, entry.get_location())
.to_exit_code()
.unwrap_or_exit();
})
} else {
iterator
- .for_each(|(i, (fle, card))| {
+ .for_each(|(i, (_, card))| {
let fmt = if scmd.is_present("find-show") {
&show_format
} else if scmd.is_present("find-list") {
@@ -336,8 +325,7 @@ fn find(rt: &Runtime) {
&list_format
};
- let hash = fle.get_hash().map(String::from).map_err_trace_exit_unwrap(1);
- let data = build_data_object_for_handlebars(i, hash, &card);
+ let data = build_data_object_for_handlebars(i, &card);
let s = fmt
.render("format", &data)
.err_from_str()
diff --git a/bin/domain/imag-contact/src/util.rs b/bin/domain/imag-contact/src/util.rs
index 12730a9..91e0078 100644
--- a/bin/domain/imag-contact/src/util.rs
+++ b/bin/domain/imag-contact/src/util.rs
@@ -18,105 +18,58 @@
//
use std::collections::BTreeMap;
-use vobject::vcard::Vcard;
-pub fn build_data_object_for_handlebars<'a>(i: usize, hash: String, vcard: &Vcard) -> BTreeMap<&'static str, String> {
- let mut data = BTreeMap::new();
- {
- data.insert("i" , format!("{}", i));
-
- // The hash (as in libimagentryref) of the contact
- data.insert("id" , hash);
-
- data.insert("ADR" , vcard.adr()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("ANNIVERSARY" , vcard.anniversary()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("BDAY" , vcard.bday()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("CATEGORIES" , vcard.categories()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("CLIENTPIDMAP" , vcard.clientpidmap()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("EMAIL" , vcard.email()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("FN" , vcard.fullname()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("GENDER" , vcard.gender()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("GEO" , vcard.geo()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("IMPP" , vcard.impp()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("KEY" , vcard.key()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("LANG" , vcard.lang()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
+use libimagcontact::deser::DeserVcard;
- data.insert("LOGO" , vcard.logo()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("MEMBER" , vcard.member()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("N" , vcard.name()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("NICKNAME" , vcard.nickname()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("NOTE" , vcard.note()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("ORG" , vcard.org()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("PHOTO" , vcard.photo()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("PRIOD" , vcard.proid()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("RELATED" , vcard.related()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("REV" , vcard.rev()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
-
- data.insert("ROLE" , vcard.role()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("SOUND" , vcard.sound()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("TEL" , vcard.tel()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
-
- data.insert("TITLE" , vcard.title()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
+pub fn build_data_object_for_handlebars<'a>(i: usize, vcard: &DeserVcard) -> BTreeMap<&'static str, String> {
+ let mut data = BTreeMap::new();
- data.insert("TZ" , vcard.tz()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
+ let process_list = |list: &Vec<String>| {
+ list.iter()
+ .map(String::clone)
+ .collect::<Vec<_>>()
+ .join(", ")
+ };
- data.insert("UID" , vcard.uid()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
+ let process_opt = |opt: Option<&String>| {
+ opt.map(String::clone).unwrap_or_else(String::new)
+ };
- data.insert("URL" , vcard.url()
- .into_iter().map(|c| c.raw().clone()).collect::<Vec<_>>().join(", "));
+ {
+ data.insert("i" , format!("{}", i));
- data.insert("VERSION" , vcard.version()
- .map(|c| c.raw().clone()).unwrap_or(String::new()));
+ // The hash (as in libimagentryref) of the contact
+ data.insert("id" , process_opt(vcard.uid()));
+ data.insert("ADR" , process_list(vcard.adr()));
+ data.insert("ANNIVERSARY" , process_opt(vcard.anniversary()));
+ data.insert("BDAY" , process_opt(vcard.bday()));
+ data.insert("CATEGORIES" , process_list(vcard.categories()));
+ data.insert("CLIENTPIDMAP" , process_opt(vcard.clientpidmap()));
+ data.insert("EMAIL" , process_list(vcard.email()));
+ data.insert("FN" , process_list(vcard.fullname()));
+ data.insert("GENDER" , process_opt(vcard.gender()));
+ data.insert("GEO" , process_list(vcard.geo()));
+ data.insert("IMPP" , process_list(vcard.impp()));
+ data.insert("KEY" , process_list(vcard.key()));
+ data.insert("LANG" , process_list(vcard.lang()));
+ data.insert("LOGO" , process_list(vcard.logo()));
+ data.insert("MEMBER" , process_list(vcard.member()));
+ data.insert("N" , process_opt(vcard.name()));
+ data.insert("NICKNAME" , process_list(vcard.nickname()));
+ data.insert("NOTE" , process_list(vcard.note()));
+ data.insert("ORG" , process_list(vcard.org()));
+ data.insert("PHOTO" , process_list(vcard.photo()));
+ data.insert("PRIOD" , process_opt(vcard.proid()));
+ data.insert("RELATED" , process_list(vcard.related()));
+ data.insert("REV" , process_opt(vcard.rev()));
+ data.insert("ROLE" , process_list(vcard.role()));
+ data.insert("SOUND" , process_list(vcard.sound()));
+ data.insert("TEL" , process_list(vcard.tel()));
+ data.insert("TITLE" , process_list(vcard.title()));
+ data.insert("TZ" , process_list(vcard.tz()));
+ data.insert("UID" , process_opt(vcard.uid()));
+ data.insert("URL" , process_list(vcard.url()));
+ data.insert("VERSION" , process_opt(vcard.version()));
}
data
diff --git a/lib/domain/libimagcontact/Cargo.toml b/lib/domain/libimagcontact/Cargo.toml
index 84ea6c0..d295248 100644
--- a/lib/domain/libimagcontact/Cargo.toml
+++ b/lib/domain/libimagcontact/Cargo.toml
@@ -25,21 +25,11 @@ log = "0.3"
toml = "0.4"
toml-query = "0.6"
vobject = "0.4"
-uuid = { version = "0.6", features = ["v4"] }
-serde = { version = "1", optional = true }
-serde_derive = { version = "1", optional = true }
+uuid = "0.6"
+serde = "1"
+serde_derive = "1"
libimagstore = { version = "0.8.0", path = "../../../lib/core/libimagstore" }
libimagerror = { version = "0.8.0", path = "../../../lib/core/libimagerror" }
libimagentryutil = { version = "0.8.0", path = "../../../lib/entry/libimagentryutil/" }
-[dependencies.libimagentryref]
-version = "0.8.0"
-path = "../../../lib/entry/libimagentryref/"
-default-features = false
-features = ["generators", "generators-sha1"]
-
-[features]
-default = []
-deser = ["serde", "serde_derive"]
-
diff --git a/lib/domain/libimagcontact/src/contact.rs b/lib/domain/libimagcontact/src/contact.rs
index 375eeed..fb58645 100644
--- a/lib/domain/libimagcontact/src/contact.rs
+++ b/lib/domain/libimagcontact/src/contact.rs
@@ -17,28 +17,27 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
-use std::ops::Deref;
-
-use vobject::Component;
+use toml::to_string as toml_to_string;
+use toml::from_str as toml_from_str;
+use toml_query::read::TomlValueReadExt;
use libimagstore::store::Entry;
-use libimagentryref::reference::Ref;
use libimagentryutil::isa::Is;
use libimagentryutil::isa::IsKindHeaderPathProvider;
+use deser::DeserVcard;
use error::Result;
-use util;
+use error::ContactError as CE;
+use error::ContactErrorKind as CEK;
/// Trait to be implemented on ::libimagstore::store::Entry
-///
-/// Based on the functionality from libimagentryref, for fetching the Ical data from disk
-pub trait Contact : Ref {
+pub trait Contact {
fn is_contact(&self) -> Result<bool>;
// getting data
- fn get_contact_data(&self) -> Result<ContactData>;
+ fn deser(&self) -> Result<DeserVcard>;
// More convenience functionality may follow
@@ -52,34 +51,18 @@ impl Contact for Entry {
self.is::<IsContact>().map_err(From::from)
}
- fn get_contact_data(&self) -> Result<ContactData> {
- let component = self
- .get_path()
- .map_err(From::from)
- .and_then(util::read_to_string)
- .and_then(util::parse)?;
-
- Ok(ContactData(component))
- }
-
-}
-
-pub struct ContactData(Component);
+ fn deser(&self) -> Result<DeserVcard> {
+ let data = self
+ .get_header()
+ .read("contact.data")?
+ .ok_or_else(|| CE::from_kind(CEK::HeaderDataMissing("contact.data")))?;
-impl ContactData {
+ // ugly hack
+ let data_str = toml_to_string(&data)?;
+ let deser : DeserVcard = toml_from_str(&data_str)?;
- pub fn into_inner(self) -> Component {
- self.0
+ Ok(deser)
}
}
-impl Deref for ContactData {
- type Target = Component;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-
diff --git a/lib/domain/libimagcontact/src/deser.rs b/lib/domain/libimagcontact/src/deser.rs
index 84855cd..aa1dc80 100644
--- a/lib/domain/libimagcontact/src/deser.rs
+++ b/lib/domain/libimagcontact/src/deser.rs
@@ -20,103 +20,127 @@
use vobject::vcard::Vcard;
/// A type which can be build from a Vcard and be serialized.
-///
-/// # Details
-///
-/// Deserializing is not supported by libimagcontact yet
-/// Elements which are "empty" (as in empty list) or optional and not present are not serialized.
-///
-#[derive(Serialize, Debug)]
+#[derive(Serialize, Deserialize, Debug)]
pub struct DeserVcard {
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
adr : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
anniversary : Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
bday : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
categories : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
clientpidmap : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
email : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
fullname : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
gender : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
geo : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
impp : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
key : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
lang : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
logo : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
member : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
name : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
nickname : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
note : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
org : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
photo : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
proid : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
related : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
rev : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
role : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
sound : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
tel : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
title : Vec<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
tz : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
uid : Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
+ #[serde(default)]
url : Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
+ #[serde(default)]
version : Option<String>
}
@@ -168,3 +192,127 @@ impl From<Vcard> for DeserVcard {
}
}
+impl DeserVcard {
+
+ pub fn adr(&self) -> &Vec<String> {
+ &self.adr
+ }
+
+ pub fn anniversary(&self) -> Option<&String> {
+ self.anniversary.as_ref()
+ }
+
+ pub fn bday(&self) -> Option<&String> {
+ self.bday.as_ref()
+ }
+
+ pub fn categories(&self) -> &Vec<String> {
+ &self.categories
+ }
+
+ pub fn clientpidmap(&self) -> Option<&String> {
+ self.clientpidmap.as_ref()
+ }
+
+ pub fn email(&self) -> &Vec<String> {
+ &self.email
+ }
+
+ pub fn fullname(&self) -> &Vec<String> {
+ &self.fullname
+ }
+
+ pub fn gender(&self) -> Option<&String> {
+ self.gender.as_ref()
+ }
+
+ pub fn geo(&self) -> &Vec<String> {
+ &self.geo
+ }
+
+ pub fn impp(&self) -> &Vec<String> {
+ &self.impp
+ }
+
+ pub fn key(&self) -> &Vec<String> {
+ &self.key
+ }
+
+ pub fn lang(&self) -> &Vec<String> {
+ &self.lang
+ }
+
+ pub fn logo(&self) -> &Vec<String> {
+ &self.logo
+ }
+
+ pub fn member(&self) -> &Vec<String> {
+ &self.member
+ }
+
+ pub fn name(&self) -> Option<&String> {
+ self.name.as_ref()
+ }
+
+ pub fn nickname(&self) -> &Vec<String> {
+ &self.nickname
+ }
+
+ pub fn note(&self) -> &Vec<String> {
+ &self.note
+ }
+
+ pub fn org(&self) -> &Vec<String> {
+ &self.org
+ }
+
+ pub fn photo(&self) -> &Vec<String> {
+ &self.photo
+ }
+
+ pub fn proid(&self) -> Option<&String> {
+ self.proid.as_ref()
+ }
+
+ pub fn related(&self) -> &Vec<String> {
+ &self.related
+ }
+
+ pub fn rev(&self) -> Option<&String> {
+ self.rev.as_ref()
+ }
+
+ pub fn role(&self) -> &Vec<String> {
+ &self.role
+ }
+
+ pub fn sound(&self) -> &Vec<String> {
+ &self.sound
+ }
+
+ pub fn tel(&self) -> &Vec<String> {
+ &self.tel
+ }
+
+ pub fn title(&self) -> &Vec<String> {
+ &self.title
+ }
+
+ pub fn tz(&self) -> &Vec<String> {
+ &self.tz
+ }
+
+ pub fn uid(&self) -> Option<&String> {
+ self.uid.as_ref()
+ }
+
+ pub fn url(&self) -> &Vec<String> {
+ &self.url
+ }
+
+ pub fn version(&self) -> Option<&String> {
+ self.version.as_ref()
+ }
+
+}
+
diff --git a/lib/domain/libimagcontact/src/error.rs b/lib/domain/libimagcontact/src/error.rs
index 37ff4c2..8eb757b 100644
--- a/lib/domain/libimagcontact/src/error.rs
+++ b/lib/domain/libimagcontact/src/error.rs
@@ -26,13 +26,14 @@ error_chain! {
links {
StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
- RefError(::libimagentryref::error::RefError, ::libimagentryref::error::RefErrorKind);
VObjectError(::vobject::error::VObjectError, ::vobject::error::VObjectErrorKind);
EntryUtilError(::libimagentryutil::error::EntryUtilError, ::libimagentryutil::error::EntryUtilErrorKind);
}
foreign_links {
Io(::std::io::Error);
+ TomlDe(::toml::de::Error);
+ TomlSer(::toml::ser::Error);
TomlQueryError(::toml_query::error::Error);
UuidError(::uuid::ParseError);
}
@@ -44,14 +45,19 @@ error_chain! {
display("Type error in header, expected {} at '{}', found other type", ty, loc)
}
+ HeaderDataMissing(datapath: &'static str) {
+ description("Data missing in header")
+ display("Data missing in header at '{}'", datapath)
+ }
+
EntryNotFound(sid: StoreId) {
description("Entry not found with StoreId")
display("Entry {:?} not found", sid)
}
- UidMissing(path: String) {
+ UidMissing(buf: String) {
description("Vcard object has no UID")
- display("Vcard at {:?} has no UID", path)
+ display("Vcard has no UID : {}", buf)
}
}
diff --git a/lib/domain/libimagcontact/src/iter.rs b/lib/domain/libimagcontact/src/iter.rs
index 8e66c83..1f99c87 100644
--- a/lib/domain/libimagcontact/src/iter.rs
+++ b/lib/domain/libimagcontact/src/iter.rs
@@ -29,13 +29,6 @@ use error::Result;
pub struct ContactIter<'a>(StoreIdIterator, &'a Store);
/// Iterator over contacts
-///
-/// As the libimagcontact works with libimagentryref in the backend, we must hold a reference to the
-/// Store here as well, so we can check whether a fetched StoreId actually points to a contact
-/// reference or not.
-///
-/// So, the Iterator `Store::get()`s the object pointed to by the StoreId and returns it if
-/// everything worked.
impl<'a> ContactIter<'a> {
pub fn new(sii: StoreIdIterator, store: &'a Store) -> ContactIter<'a> {
diff --git a/lib/domain/libimagcontact/src/lib.rs b/lib/domain/libimagcontact/src/lib.rs
index 6e55e57..87b244e 100644
--- a/lib/domain/libimagcontact/src/lib.rs
+++ b/lib/domain/libimagcontact/src/lib.rs
@@ -33,16 +33,19 @@
while_true,
)]
+#![recursion_limit="128"]
+
#[macro_use] extern crate log;
#[macro_use] extern crate error_chain;
extern crate vobject;
extern crate toml;
extern crate toml_query;
extern crate uuid;
+extern crate serde;
+#[macro_use] extern crate serde_derive;
#[macro_use] extern crate libimagstore;
extern crate libimagerror;
-extern crate libimagentryref;
#[macro_use] extern crate libimagentryutil;
module_entry_path_mod!("contact");
@@ -51,15 +54,6 @@ pub mod contact;
pub mod error;
pub mod iter;
pub mod store;
-mod util;
-
-
-#[cfg(feature = "serde")]
-extern crate serde;
-
-#[cfg(feature = "serde")]
-#[macro_use] extern crate serde_derive;
-
-#[cfg(feature = "deser")]
pub mod deser;
+mod util;
diff --git a/lib/domain/libimagcontact/src/store.rs b/lib/domain/libimagcontact/src/store.rs
index 02ac57c..88856b7 100644
--- a/lib/domain/libimagcontact/src/store.rs
+++ b/lib/domain/libimagcontact/src/store.rs
@@ -17,64 +17,38 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
-use std::path::Path;
use std::path::PathBuf;
-use std::result::Result as RResult;
-use vobject::parse_component;
+use toml::Value;
+use toml::to_string as toml_to_string;
+use toml::from_str as toml_from_str;
+use toml_query::insert::TomlValueInsertExt;
+use vobject::vcard::Vcard;
+use libimagstore::storeid::IntoStoreId;
+use libimagstore::storeid::StoreId;
use libimagstore::store::Store;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreIdIterator;
-use libimagentryref::refstore::RefStore;
-use libimagentryref::refstore::UniqueRefPathGenerator;
use libimagentryutil::isa::Is;
use contact::IsContact;
+use deser::DeserVcard;
+use module_path::ModuleEntryPath;
use error::ContactError as CE;
use error::ContactErrorKind as CEK;
use error::Result;
use util;
-pub struct UniqueContactPathGenerator;
-impl UniqueRefPathGenerator for UniqueContactPathGenerator {
- type Error = CE;
-
- /// The collection the `StoreId` should be created for
- fn collection() -> &'static str {
- "contact"
- }
-
- /// A function which should generate a unique string for a Path
- fn unique_hash<A: AsRef<Path>>(path: A) -> RResult<String, Self::Error> {
- use vobject::vcard::Vcard;
-
- debug!("Generating unique hash for path: {:?}", path.as_ref());
- util::read_to_string(path.as_ref())
- .and_then(|s| Vcard::build(&s).map_err(CE::from))
- .and_then(|card| {
- card.uid()
- .map(|u| u.raw().clone())
- .ok_or_else(|| {
- let s = path.as_ref().to_str().unwrap_or("Unknown path");
- CEK::UidMissing(String::from(s)).into()
- })
- })
- }
-
-}
-
-pub trait ContactStore<'a> : RefStore<'a> {
+pub trait ContactStore<'a> {
// creating
- fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
+ fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
+ fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
- /// Create contact ref from buffer
- ///
- /// Needs the `p` argument as we're finally creating a reference by path, the buffer is only for
- /// collecting metadata.
- fn create_from_buf<P: AsRef<Path>>(&'a self, p: P, buf: &String) -> Result<FileLockEntry<'a>>;
+ fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
+ fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>>;
// getting
@@ -82,30 +56,25 @@ pub trait ContactStore<'a> : RefStore<'a> {
}
/// The extension for the Store to work with contacts
-///
-/// The contact functionality is implemented by using the `libimagentryref` library, so basically
-/// we only reference vcard files from outside the store.
-///
-/// Because of this, we do not have an own store collection `/contacts` or something like that, but
-/// must stress the `libimagentryref` API for everything.
impl<'a> ContactStore<'a> for Store {
fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
- util::read_to_string(p).and_then(|buf| self.create_from_buf(p, &buf))
+ util::read_to_string(p).and_then(|buf| self.create_from_buf(&buf))
+ }
+
+ fn retrieve_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
+ util::read_to_string(p).and_then(|buf| self.retrieve_from_buf(&buf))
}
/// Create contact ref from buffer
- fn create_from_buf<P: AsRef<Path>>(&'a self, p: P, buf: &String) -> Result<FileLockEntry<'a>> {
- let component = parse_component(&buf)?;
- debug!("Parsed: {:?}", component);
-
- RefStore::create_ref::<UniqueContactPathGenerator, P>(self, p)
- .map_err(From::from)
- .and_then(|mut entry| {
- entry.set_isflag::<IsContact>()
- .map_err(From::from)
- .map(|_| entry)
- })
+ fn create_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
+ let (sid, value) = prepare_fetching_from_store(buf)?;
+ postprocess_fetched_entry(self.create(sid)?, value)
+ }
+
+ fn retrieve_from_buf(&'a self, buf: &str) -> Result<FileLockEntry<'a>> {
+ let (sid, value) = prepare_fetching_from_store(buf)?;
+ postprocess_fetched_entry(self.retrieve(sid)?, value)
}
fn all_contacts(&'a self) -> Result<StoreIdIterator> {
@@ -119,3 +88,30 @@ impl<'a> ContactStore<'a> for Store {
}
+/// Prepare the fetching from the store.
+///
+/// That means calculating the StoreId and the Value from the vcard data
+fn prepare_fetching_from_store(buf: &str) -> Result<(StoreId, Value)> {
+ let vcard = Vcard::build(&buf)?;
+ debug!("Parsed: {:?}", vcard);
+
+ let uid = vcard.uid().ok_or_else(|| CE::from_kind(CEK::UidMissing(buf.to_string())))?;
+
+ let value = { // dirty ugly hack
+ let serialized = DeserVcard::from(vcard);
+ let serialized = toml_to_string(&serialized)?;
+ toml_from_str::<Value>(&serialized)?
+ };
+
+ let sid = ModuleEntryPath::new(uid.raw()).into_storeid()?;
+
+ Ok((sid, value))
+}
+
+/// Postprocess the entry just fetched from the store
+fn postprocess_fetched_entry<'a>(mut entry: FileLockEntry<'a>, value: Value) -> Result<FileLockEntry<'a>> {
+ entry.set_isflag::<IsContact>()?;
+ entry.get_header_mut().insert("contact.data", value)?;
+ Ok(entry)
+}
+
diff --git a/lib/domain/libimagcontact/src/util.rs b/lib/domain/libimagcontact/src/util.rs
index 8a72b87..53e820c 100644
--- a/lib/domain/libimagcontact/src/util.rs
+++ b/lib/domain/libimagcontact/src/util.rs
@@ -24,8 +24,6 @@ use std::io::Read;
use error::Result;
-use vobject::Component;
-
pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
let mut cont = String::new();
@@ -37,9 +35,3 @@ pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
Ok(cont)
}
-/// Helper for chaining results nicely
-pub fn parse(buf: String) -> Result<Component> {
- use vobject::parse_component;
- parse_component(&buf).map_err(From::from)
-}
-