summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-10-03 14:36:50 +0200
committerMatthias Beyer <mail@beyermatthias.de>2019-10-11 21:36:43 +0200
commit92a0713ed0e33a2ca907495491acf881562f76eb (patch)
tree037fe01f04cb151e484e9a238991f04490214fc5
parent14dc03f40f373efa690d6f766e5273223bf3d765 (diff)
Add filtering for past events
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--bin/domain/imag-calendar/Cargo.toml1
-rw-r--r--bin/domain/imag-calendar/src/filters.rs86
-rw-r--r--bin/domain/imag-calendar/src/main.rs13
-rw-r--r--bin/domain/imag-calendar/src/ui.rs7
4 files changed, 104 insertions, 3 deletions
diff --git a/bin/domain/imag-calendar/Cargo.toml b/bin/domain/imag-calendar/Cargo.toml
index 7801ac80..187468f3 100644
--- a/bin/domain/imag-calendar/Cargo.toml
+++ b/bin/domain/imag-calendar/Cargo.toml
@@ -26,6 +26,7 @@ failure = "0.1"
walkdir = "2.2.8"
vobject = "0.7"
handlebars = "2"
+chrono = "0.4"
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
diff --git a/bin/domain/imag-calendar/src/filters.rs b/bin/domain/imag-calendar/src/filters.rs
new file mode 100644
index 00000000..aab19590
--- /dev/null
+++ b/bin/domain/imag-calendar/src/filters.rs
@@ -0,0 +1,86 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015-2019 Matthias Beyer <mail@beyermatthias.de> 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 chrono::NaiveDateTime;
+use failure::Fallible as Result;
+use vobject::icalendar::Event;
+
+/// Generate a filter function to filter shown events
+///
+/// If `do_filter` is false, this filter returns true all the time.
+///
+/// If an event is in the past, relative to the `today` parameter, the function returns false,
+/// else it returns true.
+///
+/// # Details
+///
+/// The date of the event is determined by using the "dtend" or "dtstamp" members of the event
+/// object. These fields are parsed to NaiveDateTime objects and then compared to the `today` object.
+///
+/// If an parsing error happens in the "dtend" parsing step, "dtstamp" is used. If this results also
+/// in a parsing error, the first error is returned.
+///
+pub fn filter_past(do_filter: bool, today: NaiveDateTime) -> impl FnOnce(&Event) -> Result<bool> {
+ move |pe| if do_filter {
+ let uid = || pe.uid()
+ .map(|uid| uid.into_raw())
+ .unwrap_or_else(|| String::from("<No UID>"));
+
+ let dtend_is_pre_today : Result<bool> = pe.dtend()
+ .map(|dtend| Ok(try_to_parse_datetime(dtend.raw())? < today))
+ .unwrap_or_else(|| Err({
+ format_err!("Entry with UID {} has no end time, cannot determine whether to list it",
+ uid())
+ }));
+
+ let dtstamp_is_pre_today : Result<bool> = pe.dtstamp()
+ .map(|dtstamp| Ok(try_to_parse_datetime(dtstamp.raw())? < today))
+ .unwrap_or_else(|| Err({
+ format_err!("Entry with UID {} has no timestamp, cannot determine whether to list it",
+ uid())
+ }));
+
+ trace!("dtend_is_pre_today = {:?}", dtend_is_pre_today);
+ trace!("dtstamp_is_pre_today = {:?}", dtstamp_is_pre_today);
+
+ match (dtend_is_pre_today, dtstamp_is_pre_today) {
+ (Ok(b), _) => return Ok(!b),
+ (_, Ok(b)) => return Ok(!b),
+ (Err(e), _) => return Err(e)
+ }
+ } else {
+ Ok(true)
+ }
+}
+
+fn try_to_parse_datetime(s: &str) -> Result<NaiveDateTime> {
+ const FORMATS : &[&'static str] = &[
+ "%Y%m%dT%H%M%S",
+ "%Y%m%dT%H%M%SZ"
+ ];
+
+ for format in FORMATS {
+ if let Ok(parsed) = NaiveDateTime::parse_from_str(s, format) {
+ return Ok(parsed);
+ }
+ }
+
+ Err(format_err!("Cannot parse datetime: {}", s))
+}
+
diff --git a/bin/domain/imag-calendar/src/main.rs b/bin/domain/imag-calendar/src/main.rs
index a94e2ee2..379374df 100644
--- a/bin/domain/imag-calendar/src/main.rs
+++ b/bin/domain/imag-calendar/src/main.rs
@@ -40,6 +40,7 @@ extern crate clap;
extern crate toml_query;
extern crate walkdir;
extern crate handlebars;
+extern crate chrono;
#[macro_use] extern crate libimagrt;
extern crate libimagcalendar;
@@ -58,6 +59,7 @@ use toml_query::read::Partial;
use toml_query::read::TomlValueReadExt;
use walkdir::DirEntry;
use walkdir::WalkDir;
+use vobject::icalendar::Event;
use libimagcalendar::store::EventStore;
use libimagerror::io::ToExitCode;
@@ -67,6 +69,7 @@ use libimagerror::trace::MapErrTrace;
use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
+mod filters;
mod ui;
mod util;
@@ -168,6 +171,8 @@ fn list(rt: &Runtime) {
let list_format = get_event_print_format("calendar.list_format", rt, &scmd)
.map_err_trace_exit_unwrap();
+ let do_filter_past = !scmd.is_present("list-past");
+
let ref_config = rt.config()
.ok_or_else(|| format_err!("No configuration, cannot continue!"))
.map_err_trace_exit_unwrap()
@@ -181,7 +186,11 @@ fn list(rt: &Runtime) {
debug!("List format: {:?}", list_format);
debug!("Ref config : {:?}", ref_config);
- let event_filter = |pefle: &ParsedEventFLE| true; // TODO: impl filtering
+ let event_filter = |e: &'_ Event| { // what a crazy hack to make the compiler happy
+ debug!("Filtering event: {:?}", e);
+ let f = filters::filter_past(do_filter_past, chrono::Local::now().naive_local());
+ f(e)
+ };
let mut listed_events = 0;
@@ -195,7 +204,6 @@ fn list(rt: &Runtime) {
.trace_unwrap_exit()
.map(|ev| ParsedEventFLE::parse(ev, &ref_config))
.trace_unwrap_exit()
- .filter(|e| event_filter(e))
.for_each(|parsed_entry| {
parsed_entry
.get_data()
@@ -223,4 +231,3 @@ fn is_not_hidden(entry: &DirEntry) -> bool {
!entry.file_name().to_str().map(|s| s.starts_with(".")).unwrap_or(false)
}
-
diff --git a/bin/domain/imag-calendar/src/ui.rs b/bin/domain/imag-calendar/src/ui.rs
index 8386357e..9792ea9b 100644
--- a/bin/domain/imag-calendar/src/ui.rs
+++ b/bin/domain/imag-calendar/src/ui.rs
@@ -67,6 +67,13 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.required(false)
.multiple(false)
.help("Override the format used to list one event"))
+
+ .arg(Arg::with_name("list-past")
+ .long("past")
+ .takes_value(false)
+ .required(false)
+ .multiple(false)
+ .help("List past events"))
)
}