From 92a0713ed0e33a2ca907495491acf881562f76eb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 3 Oct 2019 14:36:50 +0200 Subject: [PATCH] Add filtering for past events Signed-off-by: Matthias Beyer --- bin/domain/imag-calendar/Cargo.toml | 1 + bin/domain/imag-calendar/src/filters.rs | 86 +++++++++++++++++++++++++ bin/domain/imag-calendar/src/main.rs | 13 +++- bin/domain/imag-calendar/src/ui.rs | 7 ++ 4 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 bin/domain/imag-calendar/src/filters.rs 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 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 { + move |pe| if do_filter { + let uid = || pe.uid() + .map(|uid| uid.into_raw()) + .unwrap_or_else(|| String::from("")); + + let dtend_is_pre_today : Result = 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 = 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 { + 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")) ) }