From cf78f7192f4c880f10647f07c8197e9cac1010d8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Mon, 12 Feb 2018 20:11:18 +0100 Subject: [PATCH 1/3] Implement calendar library Signed-off-by: Matthias Beyer --- Cargo.toml | 1 + doc/src/05100-lib-calendar.md | 10 +++ lib/domain/libimagcalendar/Cargo.toml | 35 +++++++++ lib/domain/libimagcalendar/README.md | 1 + lib/domain/libimagcalendar/src/event.rs | 37 ++++++++++ lib/domain/libimagcalendar/src/lib.rs | 56 ++++++++++++++ lib/domain/libimagcalendar/src/store.rs | 98 +++++++++++++++++++++++++ scripts/release.sh | 1 + 8 files changed, 239 insertions(+) create mode 100644 doc/src/05100-lib-calendar.md create mode 100644 lib/domain/libimagcalendar/Cargo.toml create mode 120000 lib/domain/libimagcalendar/README.md create mode 100644 lib/domain/libimagcalendar/src/event.rs create mode 100644 lib/domain/libimagcalendar/src/lib.rs create mode 100644 lib/domain/libimagcalendar/src/store.rs diff --git a/Cargo.toml b/Cargo.toml index 7d42d5b6..97a0d53b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ members = [ "lib/core/libimagrt", "lib/core/libimagstore", "lib/domain/libimagbookmark", + "lib/domain/libimagcalendar", "lib/domain/libimagcontact", "lib/domain/libimagdiary", "lib/domain/libimaghabit", diff --git a/doc/src/05100-lib-calendar.md b/doc/src/05100-lib-calendar.md new file mode 100644 index 00000000..33a8f3f4 --- /dev/null +++ b/doc/src/05100-lib-calendar.md @@ -0,0 +1,10 @@ +## libimagcalendar + +This library helps tracking (vcard) events in imag. + +It does nothing more than create one imag entry per VEVENT UID, giving the user +the ability to "link" to each event individually. + +It uses the libimagentryref library for refering to the actual file holding the +data. + diff --git a/lib/domain/libimagcalendar/Cargo.toml b/lib/domain/libimagcalendar/Cargo.toml new file mode 100644 index 00000000..b63ad0c3 --- /dev/null +++ b/lib/domain/libimagcalendar/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "libimagcalendar" +version = "0.10.0" +authors = ["Matthias Beyer "] + +description = "Library for the imag core distribution" + +keywords = ["imag", "PIM", "personal", "information", "management"] +readme = "../../../README.md" +license = "LGPL-2.1" + +documentation = "https://matthiasbeyer.github.io/imag/imag_documentation/index.html" +repository = "https://github.com/matthiasbeyer/imag" +homepage = "http://imag-pim.org" + +[badges] +travis-ci = { repository = "matthiasbeyer/imag" } +is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" } +is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" } +maintenance = { status = "actively-developed" } + +[dependencies] +failure = "0.1" +log = "0.4" +toml = "0.5" +toml-query = "0.9" +vobject = "0.7" +chrono = "0.4" + +libimagentrylink = { version = "0.10.0", path = "../../../lib/entry/libimagentrylink" } +libimagentryref = { version = "0.10.0", path = "../../../lib/entry/libimagentryref" } +libimagentryutil = { version = "0.10.0", path = "../../../lib/entry/libimagentryutil" } +libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" } +libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" } + diff --git a/lib/domain/libimagcalendar/README.md b/lib/domain/libimagcalendar/README.md new file mode 120000 index 00000000..0d7c3f1b --- /dev/null +++ b/lib/domain/libimagcalendar/README.md @@ -0,0 +1 @@ +../../../doc/src/05100-lib-calendar.md \ No newline at end of file diff --git a/lib/domain/libimagcalendar/src/event.rs b/lib/domain/libimagcalendar/src/event.rs new file mode 100644 index 00000000..7fbc02e1 --- /dev/null +++ b/lib/domain/libimagcalendar/src/event.rs @@ -0,0 +1,37 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use failure::Fallible as Result; + +use libimagentryutil::isa::Is; +use libimagentryutil::isa::IsKindHeaderPathProvider; +use libimagstore::store::Entry; + + +provide_kindflag_path!(pub IsEvent, "calendar.event.is_event"); + +pub trait Event { + fn is_event(&self) -> Result; +} + +impl Event for Entry { + fn is_event(&self) -> Result { + self.is::() + } +} diff --git a/lib/domain/libimagcalendar/src/lib.rs b/lib/domain/libimagcalendar/src/lib.rs new file mode 100644 index 00000000..f256417f --- /dev/null +++ b/lib/domain/libimagcalendar/src/lib.rs @@ -0,0 +1,56 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +#![forbid(unsafe_code)] + +#![deny( + dead_code, + non_camel_case_types, + non_snake_case, + path_statements, + trivial_numeric_casts, + unstable_features, + unused_allocation, + unused_import_braces, + unused_imports, + unused_must_use, + unused_mut, + unused_qualifications, + while_true, +)] + +#![recursion_limit="128"] + +#[macro_use] extern crate log; +#[macro_use] extern crate failure; +extern crate vobject; +extern crate toml; +extern crate toml_query; + +#[macro_use] extern crate libimagstore; +extern crate libimagerror; +extern crate libimagentryref; +#[macro_use] extern crate libimagentryutil; + +module_entry_path_mod!("calendar"); + +pub mod event; +pub mod store; + + diff --git a/lib/domain/libimagcalendar/src/store.rs b/lib/domain/libimagcalendar/src/store.rs new file mode 100644 index 00000000..01880f51 --- /dev/null +++ b/lib/domain/libimagcalendar/src/store.rs @@ -0,0 +1,98 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2019 Matthias Beyer and contributors +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; version +// 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +// + +use std::path::Path; + +use failure::Fallible as Result; +use toml::Value; +use toml_query::insert::TomlValueInsertExt; +use vobject::ICalendar; + +use libimagentryutil::isa::Is; +use libimagentryref::reference::Config; +use libimagentryref::reference::MutRef; +use libimagentryref::hasher::default::DefaultHasher; +use libimagentryref::reference::RefFassade; +use libimagstore::store::FileLockEntry; +use libimagstore::store::Store; + +use crate::event::IsEvent; + +pub trait EventStore<'a> { + /// Imports events from a filepath + /// + /// # Note + /// + /// Because one icalendar file can theoretically hold several events, this function returns a + /// list of entries. + /// + /// # Parameters + /// + /// This function is basically a wrapper around `libimagentryref::reference::RefMut::make_ref()` + /// which also does some parsing and Store::create() ing entry objects. + /// + /// Because of the former function, this requires some parameters which are documented in the + /// documentation of this function: + /// + /// libimagentryref::reference::RefMut::make_ref() + /// + /// Normally, `force` should be set to `false`. + /// + fn import_from_path(&'a self, p: P, basepath_name: Coll, refconfig: &Config, force: bool) + -> Result>>> + where P: AsRef, + Coll: AsRef; +} + +impl<'a> EventStore<'a> for Store { + fn import_from_path(&'a self, p: P, basepath_name: Coll, refconfig: &Config, force: bool) + -> Result>>> + where P: AsRef, + Coll: AsRef + { + let text = std::fs::read_to_string(p.as_ref())?; + Ok(ICalendar::build(&text)? + .events() + .filter_map(|rresult| match rresult { + Ok(event) => Some(event), + Err(component) => { + debug!("Ignoring non-event Component in {}: {}", p.as_ref().display(), component.name); + None + } + }) + .map(|event| { + let uid = event.uid().ok_or_else(|| { + format_err!("Event in {} has no UID, but icalendar events must have one.", p.as_ref().display()) + })?; + + let sid = crate::module_path::new_id(uid.raw())?; + let uid_header = Value::String(uid.into_raw()); + + let mut entry = self.create(sid)?; + let _ = entry + .as_ref_with_hasher_mut::() + .make_ref(p.as_ref(), basepath_name.as_ref(), refconfig, force)?; + let _ = entry.get_header_mut().insert("calendar.event.uid", uid_header)?; + let _ = entry.set_isflag::()?; + Ok(entry) + }) + .collect()) + } +} + diff --git a/scripts/release.sh b/scripts/release.sh index 643eae1b..98dbba99 100644 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -29,6 +29,7 @@ CRATES=( ./lib/entry/libimagentrymarkdown ./lib/entry/libimagentryannotation ./lib/domain/libimagbookmark + ./lib/domain/libimagcalendar ./lib/domain/libimaghabit ./lib/domain/libimagnotes ./lib/domain/libimagcontact From e86f36c215a43e7f0415e79eb9227adf56769d3e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Sat, 28 Sep 2019 11:21:06 +0200 Subject: [PATCH 2/3] Add getter helper Signed-off-by: Matthias Beyer --- lib/domain/libimagcalendar/src/store.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/domain/libimagcalendar/src/store.rs b/lib/domain/libimagcalendar/src/store.rs index 01880f51..656100e5 100644 --- a/lib/domain/libimagcalendar/src/store.rs +++ b/lib/domain/libimagcalendar/src/store.rs @@ -58,6 +58,9 @@ pub trait EventStore<'a> { -> Result>>> where P: AsRef, Coll: AsRef; + + fn get_event_by_uid(&'a self, id: ID) -> Result>> + where ID: AsRef; } impl<'a> EventStore<'a> for Store { @@ -94,5 +97,11 @@ impl<'a> EventStore<'a> for Store { }) .collect()) } + + fn get_event_by_uid(&'a self, id: ID) -> Result>> + where ID: AsRef + { + self.get(crate::module_path::new_id(id.as_ref())?) + } } From b40a854c6f50761c74655d2e7da2655aed581185 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 3 Oct 2019 12:54:11 +0200 Subject: [PATCH 3/3] Add function to get all events Signed-off-by: Matthias Beyer --- lib/domain/libimagcalendar/src/store.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/domain/libimagcalendar/src/store.rs b/lib/domain/libimagcalendar/src/store.rs index 656100e5..107bdabe 100644 --- a/lib/domain/libimagcalendar/src/store.rs +++ b/lib/domain/libimagcalendar/src/store.rs @@ -31,6 +31,7 @@ use libimagentryref::hasher::default::DefaultHasher; use libimagentryref::reference::RefFassade; use libimagstore::store::FileLockEntry; use libimagstore::store::Store; +use libimagstore::iter::Entries; use crate::event::IsEvent; @@ -61,6 +62,10 @@ pub trait EventStore<'a> { fn get_event_by_uid(&'a self, id: ID) -> Result>> where ID: AsRef; + + /// Get all events + fn all_events(&'a self) -> Result>; + } impl<'a> EventStore<'a> for Store { @@ -103,5 +108,12 @@ impl<'a> EventStore<'a> for Store { { self.get(crate::module_path::new_id(id.as_ref())?) } + + /// Get all events + /// + /// Uses Store::entries(), so there might be false positives. + fn all_events(&'a self) -> Result> { + self.entries().and_then(|es| es.in_collection("calendar")) + } }