Add filtering for past events
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
14dc03f40f
commit
92a0713ed0
4 changed files with 104 additions and 3 deletions
|
@ -26,6 +26,7 @@ failure = "0.1"
|
||||||
walkdir = "2.2.8"
|
walkdir = "2.2.8"
|
||||||
vobject = "0.7"
|
vobject = "0.7"
|
||||||
handlebars = "2"
|
handlebars = "2"
|
||||||
|
chrono = "0.4"
|
||||||
|
|
||||||
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
|
||||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||||
|
|
86
bin/domain/imag-calendar/src/filters.rs
Normal file
86
bin/domain/imag-calendar/src/filters.rs
Normal file
|
@ -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))
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ extern crate clap;
|
||||||
extern crate toml_query;
|
extern crate toml_query;
|
||||||
extern crate walkdir;
|
extern crate walkdir;
|
||||||
extern crate handlebars;
|
extern crate handlebars;
|
||||||
|
extern crate chrono;
|
||||||
|
|
||||||
#[macro_use] extern crate libimagrt;
|
#[macro_use] extern crate libimagrt;
|
||||||
extern crate libimagcalendar;
|
extern crate libimagcalendar;
|
||||||
|
@ -58,6 +59,7 @@ use toml_query::read::Partial;
|
||||||
use toml_query::read::TomlValueReadExt;
|
use toml_query::read::TomlValueReadExt;
|
||||||
use walkdir::DirEntry;
|
use walkdir::DirEntry;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
use vobject::icalendar::Event;
|
||||||
|
|
||||||
use libimagcalendar::store::EventStore;
|
use libimagcalendar::store::EventStore;
|
||||||
use libimagerror::io::ToExitCode;
|
use libimagerror::io::ToExitCode;
|
||||||
|
@ -67,6 +69,7 @@ use libimagerror::trace::MapErrTrace;
|
||||||
use libimagrt::runtime::Runtime;
|
use libimagrt::runtime::Runtime;
|
||||||
use libimagrt::setup::generate_runtime_setup;
|
use libimagrt::setup::generate_runtime_setup;
|
||||||
|
|
||||||
|
mod filters;
|
||||||
mod ui;
|
mod ui;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
@ -168,6 +171,8 @@ fn list(rt: &Runtime) {
|
||||||
let list_format = get_event_print_format("calendar.list_format", rt, &scmd)
|
let list_format = get_event_print_format("calendar.list_format", rt, &scmd)
|
||||||
.map_err_trace_exit_unwrap();
|
.map_err_trace_exit_unwrap();
|
||||||
|
|
||||||
|
let do_filter_past = !scmd.is_present("list-past");
|
||||||
|
|
||||||
let ref_config = rt.config()
|
let ref_config = rt.config()
|
||||||
.ok_or_else(|| format_err!("No configuration, cannot continue!"))
|
.ok_or_else(|| format_err!("No configuration, cannot continue!"))
|
||||||
.map_err_trace_exit_unwrap()
|
.map_err_trace_exit_unwrap()
|
||||||
|
@ -181,7 +186,11 @@ fn list(rt: &Runtime) {
|
||||||
debug!("List format: {:?}", list_format);
|
debug!("List format: {:?}", list_format);
|
||||||
debug!("Ref config : {:?}", ref_config);
|
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;
|
let mut listed_events = 0;
|
||||||
|
|
||||||
|
@ -195,7 +204,6 @@ fn list(rt: &Runtime) {
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
.map(|ev| ParsedEventFLE::parse(ev, &ref_config))
|
.map(|ev| ParsedEventFLE::parse(ev, &ref_config))
|
||||||
.trace_unwrap_exit()
|
.trace_unwrap_exit()
|
||||||
.filter(|e| event_filter(e))
|
|
||||||
.for_each(|parsed_entry| {
|
.for_each(|parsed_entry| {
|
||||||
parsed_entry
|
parsed_entry
|
||||||
.get_data()
|
.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)
|
!entry.file_name().to_str().map(|s| s.starts_with(".")).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,13 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
|
||||||
.required(false)
|
.required(false)
|
||||||
.multiple(false)
|
.multiple(false)
|
||||||
.help("Override the format used to list one event"))
|
.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"))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue