Reimplement libimagtodo
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
21cc901d06
commit
775d3f0a80
7 changed files with 632 additions and 7 deletions
|
@ -20,13 +20,31 @@ is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
|
|||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[dependencies]
|
||||
task-hookrs = "0.6.0"
|
||||
uuid = "0.7.4"
|
||||
toml = "0.5.1"
|
||||
toml-query = "0.9.2"
|
||||
log = "0.4.6"
|
||||
serde_json = "1.0.39"
|
||||
failure = "0.1.5"
|
||||
failure = "0.1"
|
||||
filters = "0.3"
|
||||
log = "0.4"
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
serde_json = "1"
|
||||
toml = "0.5"
|
||||
|
||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagentryutil = { version = "0.10.0", path = "../../../lib/entry/libimagentryutil" }
|
||||
libimagutil = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
|
||||
|
||||
[dependencies.toml-query]
|
||||
version = "0.9"
|
||||
default-features = false
|
||||
features = ["typed"]
|
||||
|
||||
[dependencies.chrono]
|
||||
version = "0.4"
|
||||
default-features = false
|
||||
features = ["serde"]
|
||||
|
||||
[dependencies.uuid]
|
||||
version = "0.7"
|
||||
default-features = false
|
||||
features = ["serde", "v4"]
|
||||
|
||||
|
|
138
lib/domain/libimagtodo/src/entry.rs
Normal file
138
lib/domain/libimagtodo/src/entry.rs
Normal file
|
@ -0,0 +1,138 @@
|
|||
//
|
||||
// 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 libimagentryutil::isa::Is;
|
||||
use libimagentryutil::isa::IsKindHeaderPathProvider;
|
||||
use libimagstore::store::Entry;
|
||||
use libimagutil::date::datetime_from_string;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use failure::ResultExt;
|
||||
use chrono::NaiveDateTime;
|
||||
use toml_query::read::Partial;
|
||||
use toml_query::read::TomlValueReadExt;
|
||||
use toml_query::insert::TomlValueInsertExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::status::Status;
|
||||
use crate::priority::Priority;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub(crate) struct TodoHeader {
|
||||
pub(crate) uuid: Uuid,
|
||||
pub(crate) status: Status,
|
||||
pub(crate) scheduled: Option<String>,
|
||||
pub(crate) hidden: Option<String>,
|
||||
pub(crate) due: Option<String>,
|
||||
pub(crate) priority: Option<Priority>,
|
||||
}
|
||||
|
||||
impl<'a> Partial<'a> for TodoHeader {
|
||||
const LOCATION: &'static str = "todo";
|
||||
type Output = Self;
|
||||
}
|
||||
|
||||
pub trait Todo {
|
||||
fn is_todo(&self) -> Result<bool>;
|
||||
fn get_uuid(&self) -> Result<Uuid>;
|
||||
fn get_status(&self) -> Result<Status>;
|
||||
fn set_status(&mut self, status: Status) -> Result<()>;
|
||||
fn get_scheduled(&self) -> Result<Option<NaiveDateTime>>;
|
||||
fn set_scheduled(&mut self, scheduled: NaiveDateTime) -> Result<()>;
|
||||
fn get_hidden(&self) -> Result<Option<NaiveDateTime>>;
|
||||
fn set_hidden(&mut self, hidden: NaiveDateTime) -> Result<()>;
|
||||
fn get_due(&self) -> Result<Option<NaiveDateTime>>;
|
||||
fn set_due(&mut self, due: NaiveDateTime) -> Result<()>;
|
||||
fn get_priority(&self) -> Result<Option<Priority>>;
|
||||
fn set_priority(&mut self, prio: Priority) -> Result<()>;
|
||||
}
|
||||
|
||||
provide_kindflag_path!(pub IsTodo, "todo.is_todo");
|
||||
|
||||
impl Todo for Entry {
|
||||
fn is_todo(&self) -> Result<bool> {
|
||||
self.is::<IsTodo>().context("Cannot check whether Entry is a todo").map_err(From::from)
|
||||
}
|
||||
|
||||
fn get_uuid(&self) -> Result<Uuid> {
|
||||
get_header(self).map(|hdr| hdr.uuid)
|
||||
}
|
||||
|
||||
fn get_status(&self) -> Result<Status> {
|
||||
get_header(self).map(|hdr| hdr.status)
|
||||
}
|
||||
|
||||
fn set_status(&mut self, status: Status) -> Result<()> {
|
||||
self.get_header_mut().insert_serialized("todo.status", status)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_scheduled(&self) -> Result<Option<NaiveDateTime>> {
|
||||
get_optional_ndt(self, |hdr| hdr.scheduled)
|
||||
}
|
||||
|
||||
fn set_scheduled(&mut self, scheduled: NaiveDateTime) -> Result<()> {
|
||||
self.get_header_mut().insert_serialized("todo.scheduled", scheduled)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_hidden(&self) -> Result<Option<NaiveDateTime>> {
|
||||
get_optional_ndt(self, |hdr| hdr.hidden)
|
||||
}
|
||||
|
||||
fn set_hidden(&mut self, hidden: NaiveDateTime) -> Result<()> {
|
||||
self.get_header_mut().insert_serialized("todo.hidden", hidden)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_due(&self) -> Result<Option<NaiveDateTime>> {
|
||||
get_optional_ndt(self, |hdr| hdr.due)
|
||||
}
|
||||
|
||||
fn set_due(&mut self, due: NaiveDateTime) -> Result<()> {
|
||||
self.get_header_mut().insert_serialized("todo.due", due)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_priority(&self) -> Result<Option<Priority>> {
|
||||
get_header(self).map(|hdr| hdr.priority)
|
||||
}
|
||||
|
||||
fn set_priority(&mut self, priority: Priority) -> Result<()> {
|
||||
self.get_header_mut().insert_serialized("todo.priority", priority)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn get_header(entry: &Entry) -> Result<TodoHeader> {
|
||||
entry.get_header()
|
||||
.read_partial::<TodoHeader>()?
|
||||
.ok_or_else(|| {
|
||||
format_err!("{} does not contain a TODO header", entry.get_location())
|
||||
})
|
||||
}
|
||||
|
||||
fn get_optional_ndt<F>(entry: &Entry, extractor: F)
|
||||
-> Result<Option<NaiveDateTime>>
|
||||
where F: FnOnce(TodoHeader) -> Option<String>
|
||||
{
|
||||
get_header(entry).map(extractor)?.map(datetime_from_string).transpose().map_err(Error::from)
|
||||
}
|
133
lib/domain/libimagtodo/src/iter.rs
Normal file
133
lib/domain/libimagtodo/src/iter.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
//
|
||||
// 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 std::result::Result as RResult;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use failure::Error;
|
||||
use filters::failable::filter::FailableFilter;
|
||||
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::store::Entry;
|
||||
|
||||
use crate::entry::Todo;
|
||||
use crate::status::Status;
|
||||
use crate::priority::Priority;
|
||||
|
||||
/// Iterator adaptor which filters an Iterator<Item = FileLockEntry> so that only todos are left
|
||||
pub struct OnlyTodos<'a>(Box<dyn Iterator<Item = FileLockEntry<'a>>>);
|
||||
|
||||
impl<'a> OnlyTodos<'a> {
|
||||
pub fn new(it: Box<dyn Iterator<Item = FileLockEntry<'a>>>) -> Self {
|
||||
OnlyTodos(it)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for OnlyTodos<'a> {
|
||||
type Item = Result<FileLockEntry<'a>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
while let Some(next) = self.0.next() {
|
||||
match next.is_todo() {
|
||||
Ok(true) => return Some(Ok(next)),
|
||||
Ok(false) => continue,
|
||||
Err(e) => return Some(Err(e)),
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper filter type
|
||||
///
|
||||
/// Can be used to filter an Iterator<Item = FileLockEntry> of Todos by status
|
||||
///
|
||||
pub struct StatusFilter(Status);
|
||||
|
||||
impl FailableFilter<Entry> for StatusFilter {
|
||||
type Error = Error;
|
||||
|
||||
fn filter(&self, entry: &Entry) -> RResult<bool, Self::Error> {
|
||||
Ok(entry.get_status()? == self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper filter type
|
||||
///
|
||||
/// Can be used to filter an Iterator<Item = FileLockEntry> of Todos for scheduled todos
|
||||
///
|
||||
pub struct IsScheduledFilter;
|
||||
|
||||
impl FailableFilter<Entry> for IsScheduledFilter {
|
||||
type Error = Error;
|
||||
|
||||
fn filter(&self, entry: &Entry) -> RResult<bool, Self::Error> {
|
||||
entry.get_scheduled().map(|s| s.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper filter type
|
||||
///
|
||||
/// Can be used to filter an Iterator<Item = FileLockEntry> of Todos for hidden todos
|
||||
///
|
||||
pub struct IsHiddenFilter;
|
||||
|
||||
impl FailableFilter<Entry> for IsHiddenFilter {
|
||||
type Error = Error;
|
||||
|
||||
fn filter(&self, entry: &Entry) -> RResult<bool, Self::Error> {
|
||||
entry.get_hidden().map(|s| s.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Helper filter type
|
||||
///
|
||||
/// Can be used to filter an Iterator<Item = FileLockEntry> of Todos for due todos
|
||||
///
|
||||
pub struct IsDueFilter;
|
||||
|
||||
impl FailableFilter<Entry> for IsDueFilter {
|
||||
type Error = Error;
|
||||
|
||||
fn filter(&self, entry: &Entry) -> RResult<bool, Self::Error> {
|
||||
entry.get_due().map(|s| s.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Helper filter type
|
||||
///
|
||||
/// Can be used to filter an Iterator<Item = FileLockEntry> of Todos for priority
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// If no priority is set for the entry, this filters out the entry
|
||||
///
|
||||
pub struct PriorityFilter(Priority);
|
||||
|
||||
impl FailableFilter<Entry> for PriorityFilter {
|
||||
type Error = Error;
|
||||
|
||||
fn filter(&self, entry: &Entry) -> RResult<bool, Self::Error> {
|
||||
Ok(entry.get_priority()?.map(|p| p == self.0).unwrap_or(false))
|
||||
}
|
||||
}
|
||||
|
44
lib/domain/libimagtodo/src/lib.rs
Normal file
44
lib/domain/libimagtodo/src/lib.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// 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
|
||||
//
|
||||
|
||||
|
||||
extern crate chrono;
|
||||
extern crate serde;
|
||||
extern crate toml;
|
||||
extern crate toml_query;
|
||||
extern crate uuid;
|
||||
extern crate filters;
|
||||
|
||||
#[macro_use] extern crate serde_derive;
|
||||
#[macro_use] extern crate failure;
|
||||
#[macro_use] extern crate log;
|
||||
|
||||
extern crate libimagerror;
|
||||
extern crate libimagutil;
|
||||
#[macro_use] extern crate libimagstore;
|
||||
#[macro_use] extern crate libimagentryutil;
|
||||
|
||||
pub mod entry;
|
||||
pub mod iter;
|
||||
pub mod priority;
|
||||
pub mod status;
|
||||
pub mod store;
|
||||
|
||||
module_entry_path_mod!("todo");
|
||||
|
68
lib/domain/libimagtodo/src/priority.rs
Normal file
68
lib/domain/libimagtodo/src/priority.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// 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 std::cmp::PartialOrd;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Priority {
|
||||
#[serde(rename = "h")]
|
||||
High,
|
||||
|
||||
#[serde(rename = "m")]
|
||||
Medium,
|
||||
|
||||
#[serde(rename = "l")]
|
||||
Low,
|
||||
}
|
||||
|
||||
impl Priority {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Priority::High => "h",
|
||||
Priority::Medium => "m",
|
||||
Priority::Low => "l",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Priority {
|
||||
fn partial_cmp(&self, other: &Priority) -> Option<Ordering> {
|
||||
Some(match (self, other) {
|
||||
(Priority::Low, Priority::Low) => Ordering::Equal,
|
||||
(Priority::Low, Priority::Medium) => Ordering::Less,
|
||||
(Priority::Low, Priority::High) => Ordering::Less,
|
||||
|
||||
(Priority::Medium, Priority::Low) => Ordering::Greater,
|
||||
(Priority::Medium, Priority::Medium) => Ordering::Equal,
|
||||
(Priority::Medium, Priority::High) => Ordering::Less,
|
||||
|
||||
(Priority::High, Priority::Low) => Ordering::Greater,
|
||||
(Priority::High, Priority::Medium) => Ordering::Greater,
|
||||
(Priority::High, Priority::High) => Ordering::Equal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Priority {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(&other).unwrap() // save by impl above
|
||||
}
|
||||
}
|
||||
|
72
lib/domain/libimagtodo/src/status.rs
Normal file
72
lib/domain/libimagtodo/src/status.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// 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 failure::Fallible as Result;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Status {
|
||||
#[serde(rename = "pending")]
|
||||
Pending,
|
||||
|
||||
#[serde(rename = "done")]
|
||||
Done,
|
||||
|
||||
#[serde(rename = "deleted")]
|
||||
Deleted,
|
||||
}
|
||||
|
||||
impl Status {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Status::Pending => "pending",
|
||||
Status::Done => "done",
|
||||
Status::Deleted => "deleted",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(s: &str) -> Result<Self> {
|
||||
match s {
|
||||
"pending" => Ok(Status::Pending),
|
||||
"done" => Ok(Status::Done),
|
||||
"deleted" => Ok(Status::Deleted),
|
||||
other => Err(format_err!("{} is not a valid status", other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serializing() {
|
||||
assert_eq!(Status::Pending.as_str(), "pending");
|
||||
assert_eq!(Status::Done.as_str(), "done");
|
||||
assert_eq!(Status::Deleted.as_str(), "deleted");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deserializing() {
|
||||
assert_eq!(Status::from_str("pending").unwrap(), Status::Pending);
|
||||
assert_eq!(Status::from_str("done").unwrap(), Status::Done);
|
||||
assert_eq!(Status::from_str("deleted").unwrap(), Status::Deleted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serializing_deserializing() {
|
||||
assert_eq!(Status::Pending.as_str(), Status::from_str("pending").unwrap().as_str());
|
||||
assert_eq!(Status::Done.as_str(), Status::from_str("done").unwrap().as_str());
|
||||
assert_eq!(Status::Deleted.as_str(), Status::from_str("deleted").unwrap().as_str());
|
||||
}
|
152
lib/domain/libimagtodo/src/store.rs
Normal file
152
lib/domain/libimagtodo/src/store.rs
Normal file
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// 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 std::result::Result as RResult;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use chrono::NaiveDateTime;
|
||||
use uuid::Uuid;
|
||||
use toml_query::insert::TomlValueInsertExt;
|
||||
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::iter::Entries;
|
||||
use libimagutil::date::datetime_to_string;
|
||||
use libimagentryutil::isa::Is;
|
||||
|
||||
use crate::status::Status;
|
||||
use crate::priority::Priority;
|
||||
use crate::entry::TodoHeader;
|
||||
use crate::entry::IsTodo;
|
||||
|
||||
pub trait TodoStore<'a> {
|
||||
fn create_todo(&'a self,
|
||||
status: Status,
|
||||
scheduled: Option<NaiveDateTime>,
|
||||
hidden: Option<NaiveDateTime>,
|
||||
due: Option<NaiveDateTime>,
|
||||
prio: Option<Priority>,
|
||||
check_sanity: bool) -> Result<FileLockEntry<'a>>;
|
||||
|
||||
fn get_todo_by_uuid(&'a self, uuid: &Uuid) -> Result<Option<FileLockEntry<'a>>>;
|
||||
|
||||
fn get_todos(&self) -> Result<Entries>;
|
||||
}
|
||||
|
||||
impl<'a> TodoStore<'a> for Store {
|
||||
|
||||
/// Create a new todo entry
|
||||
///
|
||||
/// # Warning
|
||||
///
|
||||
/// If check_sanity is set to false, this does not sanity-check the scheduled/hidden/due dates.
|
||||
/// This might result in unintended behaviour (hidden after due date, scheduled before hidden
|
||||
/// date... etc)
|
||||
///
|
||||
/// An user of this function might want to use `date_sanity_check()` to perform sanity checks
|
||||
/// before calling TodoStore::create_todo() and show the Err(String) as a warning to user in an
|
||||
/// interactive way.
|
||||
fn create_todo(&'a self,
|
||||
status: Status,
|
||||
scheduled: Option<NaiveDateTime>,
|
||||
hidden: Option<NaiveDateTime>,
|
||||
due: Option<NaiveDateTime>,
|
||||
prio: Option<Priority>,
|
||||
check_sanity: bool) -> Result<FileLockEntry<'a>>
|
||||
{
|
||||
if check_sanity {
|
||||
trace!("Checking sanity before creating todo");
|
||||
if let Err(s) = date_sanity_check(scheduled.as_ref(), hidden.as_ref(), due.as_ref()) {
|
||||
trace!("Not sane.");
|
||||
return Err(format_err!("{}", s))
|
||||
}
|
||||
}
|
||||
|
||||
let uuid = Uuid::new_v4();
|
||||
let uuid_s = format!("{}", uuid.to_hyphenated_ref()); // TODO: not how it is supposed to be
|
||||
debug!("Created new UUID for todo = {}", uuid_s);
|
||||
|
||||
let mut entry = crate::module_path::new_id(uuid_s).and_then(|id| self.create(id))?;
|
||||
|
||||
let header = TodoHeader {
|
||||
uuid,
|
||||
status,
|
||||
scheduled: scheduled.as_ref().map(datetime_to_string),
|
||||
hidden: hidden.as_ref().map(datetime_to_string),
|
||||
due: due.as_ref().map(datetime_to_string),
|
||||
priority: prio
|
||||
};
|
||||
|
||||
debug!("Created header for todo: {:?}", header);
|
||||
|
||||
let _ = entry.get_header_mut().insert_serialized("todo", header)?;
|
||||
let _ = entry.set_isflag::<IsTodo>()?;
|
||||
|
||||
Ok(entry)
|
||||
}
|
||||
|
||||
fn get_todo_by_uuid(&'a self, uuid: &Uuid) -> Result<Option<FileLockEntry<'a>>> {
|
||||
let uuid_s = format!("{}", uuid.to_hyphenated_ref()); // TODO: not how it is supposed to be
|
||||
debug!("Created new UUID for todo = {}", uuid_s);
|
||||
let id = crate::module_path::new_id(uuid_s)?;
|
||||
self.get(id)
|
||||
}
|
||||
|
||||
/// Get all todos using Store::entries()
|
||||
fn get_todos(&self) -> Result<Entries> {
|
||||
self.entries().and_then(|es| es.in_collection("todo"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform a sanity check on the scheduled/hidden/due dates
|
||||
///
|
||||
/// This function returns a String as error, which can be shown as a warning to the user or as an
|
||||
/// error.
|
||||
pub fn date_sanity_check(scheduled: Option<&NaiveDateTime>,
|
||||
hidden: Option<&NaiveDateTime>,
|
||||
due: Option<&NaiveDateTime>)
|
||||
-> RResult<(), String>
|
||||
{
|
||||
if let (Some(sched), Some(hid)) = (scheduled.as_ref(), hidden.as_ref()) {
|
||||
if sched > hid {
|
||||
return Err(format!("Scheduled date after hidden date: {s}, {h}",
|
||||
s = sched,
|
||||
h = hid))
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(hid), Some(due)) = (hidden.as_ref(), due.as_ref()) {
|
||||
if hid > due {
|
||||
return Err(format!("Hidden date after due date: {h}, {d}",
|
||||
h = hid,
|
||||
d = due))
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(sched), Some(due)) = (scheduled.as_ref(), due.as_ref()) {
|
||||
if sched > due {
|
||||
return Err(format!("Scheduled date after due date: {s}, {d}",
|
||||
s = sched,
|
||||
d = due))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in a new issue