summaryrefslogtreecommitdiffstats
path: root/lib/domain/libimagdiary/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/domain/libimagdiary/src')
-rw-r--r--lib/domain/libimagdiary/src/config.rs43
-rw-r--r--lib/domain/libimagdiary/src/diary.rs128
-rw-r--r--lib/domain/libimagdiary/src/diaryid.rs257
-rw-r--r--lib/domain/libimagdiary/src/entry.rs90
-rw-r--r--lib/domain/libimagdiary/src/error.rs38
-rw-r--r--lib/domain/libimagdiary/src/is_in_diary.rs44
-rw-r--r--lib/domain/libimagdiary/src/iter.rs132
-rw-r--r--lib/domain/libimagdiary/src/lib.rs62
-rw-r--r--lib/domain/libimagdiary/src/result.rs24
-rw-r--r--lib/domain/libimagdiary/src/viewer.rs64
10 files changed, 882 insertions, 0 deletions
diff --git a/lib/domain/libimagdiary/src/config.rs b/lib/domain/libimagdiary/src/config.rs
new file mode 100644
index 00000000..c2a6a980
--- /dev/null
+++ b/lib/domain/libimagdiary/src/config.rs
@@ -0,0 +1,43 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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 toml::Value;
+
+use libimagrt::runtime::Runtime;
+
+use toml_query::read::TomlValueReadExt;
+
+pub fn get_default_diary_name(rt: &Runtime) -> Option<String> {
+ get_diary_config_section(rt)
+ .and_then(|config| {
+ match config.read(&String::from("default_diary")) {
+ Ok(Some(&Value::String(ref s))) => Some(s.clone()),
+ _ => None,
+ }
+ })
+}
+
+pub fn get_diary_config_section<'a>(rt: &'a Runtime) -> Option<&'a Value> {
+ rt.config()
+ .map(|config| config.config())
+ .and_then(|config| match config.read(&String::from("diary")) {
+ Ok(x) => x,
+ Err(_) => None,
+ })
+}
diff --git a/lib/domain/libimagdiary/src/diary.rs b/lib/domain/libimagdiary/src/diary.rs
new file mode 100644
index 00000000..431b6320
--- /dev/null
+++ b/lib/domain/libimagdiary/src/diary.rs
@@ -0,0 +1,128 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::Ordering;
+
+use libimagstore::store::Store;
+use libimagstore::storeid::IntoStoreId;
+use libimagerror::trace::trace_error;
+
+use chrono::offset::Local;
+use chrono::Datelike;
+use itertools::Itertools;
+use chrono::naive::NaiveDateTime;
+
+use entry::Entry;
+use diaryid::DiaryId;
+use error::DiaryError as DE;
+use error::DiaryErrorKind as DEK;
+use result::Result;
+use iter::DiaryEntryIterator;
+use is_in_diary::IsInDiary;
+
+#[derive(Debug)]
+pub struct Diary<'a> {
+ store: &'a Store,
+ name: &'a str,
+}
+
+impl<'a> Diary<'a> {
+
+ pub fn open(store: &'a Store, name: &'a str) -> Diary<'a> {
+ Diary {
+ store: store,
+ name: name,
+ }
+ }
+
+ // create or get a new entry for today
+ pub fn new_entry_today(&self) -> Result<Entry> {
+ let dt = Local::now();
+ let ndt = dt.naive_local();
+ let id = DiaryId::new(String::from(self.name), ndt.year(), ndt.month(), ndt.day(), 0, 0);
+ self.new_entry_by_id(id)
+ }
+
+ pub fn new_entry_by_id(&self, id: DiaryId) -> Result<Entry> {
+ self.retrieve(id.with_diary_name(String::from(self.name)))
+ }
+
+ pub fn retrieve(&self, id: DiaryId) -> Result<Entry> {
+ id.into_storeid()
+ .and_then(|id| self.store.retrieve(id))
+ .map(|fle| Entry::new(fle))
+ .map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
+ }
+
+ // Get an iterator for iterating over all entries
+ pub fn entries(&self) -> Result<DiaryEntryIterator<'a>> {
+ self.store
+ .retrieve_for_module("diary")
+ .map(|iter| DiaryEntryIterator::new(self.name, self.store, iter))
+ .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
+ }
+
+ pub fn delete_entry(&self, entry: Entry) -> Result<()> {
+ if !entry.is_in_diary(self.name) {
+ return Err(DE::new(DEK::EntryNotInDiary, None));
+ }
+ let id = entry.get_location().clone();
+ drop(entry);
+
+ self.store.delete(id)
+ .map_err(|e| DE::new(DEK::StoreWriteError, Some(Box::new(e))))
+ }
+
+ pub fn get_youngest_entry(&self) -> Option<Result<Entry>> {
+ match self.entries() {
+ Err(e) => Some(Err(e)),
+ Ok(entries) => {
+ entries.sorted_by(|a, b| {
+ match (a, b) {
+ (&Ok(ref a), &Ok(ref b)) => {
+ let a : NaiveDateTime = a.diary_id().into();
+ let b : NaiveDateTime = b.diary_id().into();
+
+ a.cmp(&b)
+ },
+
+ (&Ok(_), &Err(ref e)) => {
+ trace_error(e);
+ Ordering::Less
+ },
+ (&Err(ref e), &Ok(_)) => {
+ trace_error(e);
+ Ordering::Greater
+ },
+ (&Err(ref e1), &Err(ref e2)) => {
+ trace_error(e1);
+ trace_error(e2);
+ Ordering::Equal
+ },
+ }
+ }).into_iter().next()
+ }
+ }
+ }
+
+ pub fn name(&self) -> &'a str {
+ &self.name
+ }
+}
+
diff --git a/lib/domain/libimagdiary/src/diaryid.rs b/lib/domain/libimagdiary/src/diaryid.rs
new file mode 100644
index 00000000..da1afc42
--- /dev/null
+++ b/lib/domain/libimagdiary/src/diaryid.rs
@@ -0,0 +1,257 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::convert::Into;
+use std::fmt::{Display, Formatter, Error as FmtError};
+
+use chrono::naive::NaiveDateTime;
+use chrono::naive::NaiveTime;
+use chrono::naive::NaiveDate;
+use chrono::Datelike;
+use chrono::Timelike;
+
+use libimagstore::storeid::StoreId;
+use libimagstore::storeid::IntoStoreId;
+use libimagstore::store::Result as StoreResult;
+
+use error::DiaryError as DE;
+use error::DiaryErrorKind as DEK;
+use error::MapErrInto;
+use libimagerror::into::IntoError;
+
+use module_path::ModuleEntryPath;
+
+#[derive(Debug, Clone)]
+pub struct DiaryId {
+ name: String,
+ year: i32,
+ month: u32,
+ day: u32,
+ hour: u32,
+ minute: u32,
+}
+
+impl DiaryId {
+
+ pub fn new(name: String, y: i32, m: u32, d: u32, h: u32, min: u32) -> DiaryId {
+ DiaryId {
+ name: name,
+ year: y,
+ month: m,
+ day: d,
+ hour: h,
+ minute: min,
+ }
+ }
+
+ pub fn from_datetime<DT: Datelike + Timelike>(diary_name: String, dt: DT) -> DiaryId {
+ DiaryId::new(diary_name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
+ }
+
+ pub fn diary_name(&self) -> &String {
+ &self.name
+ }
+
+ pub fn year(&self) -> i32 {
+ self.year
+ }
+
+ pub fn month(&self) -> u32 {
+ self.month
+ }
+
+ pub fn day(&self) -> u32 {
+ self.day
+ }
+
+ pub fn hour(&self) -> u32 {
+ self.hour
+ }
+
+ pub fn minute(&self) -> u32 {
+ self.minute
+ }
+
+ pub fn with_diary_name(mut self, name: String) -> DiaryId {
+ self.name = name;
+ self
+ }
+
+ pub fn with_year(mut self, year: i32) -> DiaryId {
+ self.year = year;
+ self
+ }
+
+ pub fn with_month(mut self, month: u32) -> DiaryId {
+ self.month = month;
+ self
+ }
+
+ pub fn with_day(mut self, day: u32) -> DiaryId {
+ self.day = day;
+ self
+ }
+
+ pub fn with_hour(mut self, hour: u32) -> DiaryId {
+ self.hour = hour;
+ self
+ }
+
+ pub fn with_minute(mut self, minute: u32) -> DiaryId {
+ self.minute = minute;
+ self
+ }
+
+ pub fn now(name: String) -> DiaryId {
+ use chrono::offset::Local;
+
+ let now = Local::now();
+ let now_date = now.date().naive_local();
+ let now_time = now.time();
+ let dt = NaiveDateTime::new(now_date, now_time);
+
+ DiaryId::new(name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
+ }
+
+}
+
+impl Default for DiaryId {
+
+ /// Create a default DiaryId which is a diaryid for a diary named "default" with
+ /// time = 0000-00-00 00:00:00
+ fn default() -> DiaryId {
+ let dt = NaiveDateTime::new(NaiveDate::from_ymd(0, 0, 0), NaiveTime::from_hms(0, 0, 0));
+ DiaryId::from_datetime(String::from("default"), dt)
+ }
+}
+
+impl IntoStoreId for DiaryId {
+
+ fn into_storeid(self) -> StoreResult<StoreId> {
+ let s : String = self.into();
+ ModuleEntryPath::new(s).into_storeid()
+ }
+
+}
+
+impl Into<String> for DiaryId {
+
+ fn into(self) -> String {
+ format!("{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
+ self.name, self.year, self.month, self.day, self.hour, self.minute)
+ }
+
+}
+
+impl Display for DiaryId {
+
+ fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
+ write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
+ self.name, self.year, self.month, self.day, self.hour, self.minute)
+ }
+
+}
+
+impl Into<NaiveDateTime> for DiaryId {
+
+ fn into(self) -> NaiveDateTime {
+ let d = NaiveDate::from_ymd(self.year, self.month, self.day);
+ let t = NaiveTime::from_hms(self.hour, self.minute, 0);
+ NaiveDateTime::new(d, t)
+ }
+
+}
+
+pub trait FromStoreId : Sized {
+
+ fn from_storeid(&StoreId) -> Result<Self, DE>;
+
+}
+
+use std::path::Component;
+
+fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str, DE> {
+ match com {
+ Component::Normal(s) => Some(s),
+ _ => None,
+ }.and_then(|s| s.to_str())
+ .ok_or(DEK::IdParseError.into_error())
+}
+
+impl FromStoreId for DiaryId {
+
+ fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> {
+ use std::str::FromStr;
+
+ use std::path::Components;
+ use std::iter::Rev;
+
+ fn next_component<'a>(components: &'a mut Rev<Components>) -> Result<&'a str, DE> {
+ components.next()
+ .ok_or(DEK::IdParseError.into_error())
+ .and_then(component_to_str)
+ }
+
+ let mut cmps = s.components().rev();
+
+ let (hour, minute) = try!(next_component(&mut cmps).and_then(|time| {
+ let mut time = time.split(":");
+ let hour = time.next().and_then(|s| FromStr::from_str(s).ok());
+ let minute = time.next()
+ .and_then(|s| s.split("~").next())
+ .and_then(|s| FromStr::from_str(s).ok());
+
+ debug!("Hour = {:?}", hour);
+ debug!("Minute = {:?}", minute);
+
+ match (hour, minute) {
+ (Some(h), Some(m)) => Ok((h, m)),
+ _ => return Err(DE::new(DEK::IdParseError, None)),
+ }
+ }));
+
+ let day: Result<u32,_> = next_component(&mut cmps)
+ .and_then(|s| s.parse::<u32>()
+ .map_err_into(DEK::IdParseError));
+
+ let month: Result<u32,_> = next_component(&mut cmps)
+ .and_then(|s| s.parse::<u32>()
+ .map_err_into(DEK::IdParseError));
+
+ let year: Result<i32,_> = next_component(&mut cmps)
+ .and_then(|s| s.parse::<i32>()
+ .map_err_into(DEK::IdParseError));
+
+ let name = next_component(&mut cmps).map(String::from);
+
+ debug!("Day = {:?}", day);
+ debug!("Month = {:?}", month);
+ debug!("Year = {:?}", year);
+ debug!("Name = {:?}", name);
+
+ let day = try!(day);
+ let month = try!(month);
+ let year = try!(year);
+ let name = try!(name);
+
+ Ok(DiaryId::new(name, year, month, day, hour, minute))
+ }
+
+}
+
diff --git a/lib/domain/libimagdiary/src/entry.rs b/lib/domain/libimagdiary/src/entry.rs
new file mode 100644
index 00000000..0148b59d
--- /dev/null
+++ b/lib/domain/libimagdiary/src/entry.rs
@@ -0,0 +1,90 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::ops::Deref;
+use std::ops::DerefMut;
+
+use libimagstore::store::FileLockEntry;
+use libimagentryedit::edit::Edit;
+use libimagentryedit::result::Result as EditResult;
+use libimagrt::runtime::Runtime;
+
+use diaryid::DiaryId;
+use diaryid::FromStoreId;
+
+#[derive(Debug)]
+pub struct Entry<'a>(FileLockEntry<'a>);
+
+impl<'a> Deref for Entry<'a> {
+ type Target = FileLockEntry<'a>;
+
+ fn deref(&self) -> &FileLockEntry<'a> {
+ &self.0
+ }
+
+}
+
+impl<'a> DerefMut for Entry<'a> {
+
+ fn deref_mut(&mut self) -> &mut FileLockEntry<'a> {
+ &mut self.0
+ }
+
+}
+
+impl<'a> Entry<'a> {
+
+ pub fn new(fle: FileLockEntry<'a>) -> Entry<'a> {
+ Entry(fle)
+ }
+
+ /// Get the diary id for this entry.
+ ///
+ /// TODO: calls Option::unwrap() as it assumes that an existing Entry has an ID that is parsable
+ pub fn diary_id(&self) -> DiaryId {
+ DiaryId::from_storeid(&self.0.get_location().clone()).unwrap()
+ }
+
+}
+
+impl<'a> Into<FileLockEntry<'a>> for Entry<'a> {
+
+ fn into(self) -> FileLockEntry<'a> {
+ self.0
+ }
+
+}
+
+impl<'a> From<FileLockEntry<'a>> for Entry<'a> {
+
+ fn from(fle: FileLockEntry<'a>) -> Entry<'a> {
+ Entry::new(fle)
+ }
+
+}
+
+impl<'a> Edit for Entry<'a> {
+
+ fn edit_content(&mut self, rt: &Runtime) -> EditResult<()> {
+ self.0.edit_content(rt)
+ }
+
+}
+
+
diff --git a/lib/domain/libimagdiary/src/error.rs b/lib/domain/libimagdiary/src/error.rs
new file mode 100644
index 00000000..b5406b12
--- /dev/null
+++ b/lib/domain/libimagdiary/src/error.rs
@@ -0,0 +1,38 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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
+//
+
+generate_error_module!(
+ generate_error_types!(DiaryError, DiaryErrorKind,
+ StoreWriteError => "Error writing store",
+ StoreReadError => "Error reading store",
+ CannotFindDiary => "Cannot find diary",
+ CannotCreateNote => "Cannot create Note object for diary entry",
+ DiaryEditError => "Cannot edit diary entry",
+ PathConversionError => "Error while converting paths internally",
+ EntryNotInDiary => "Entry not in Diary",
+ IOError => "IO Error",
+ ViewError => "Error viewing diary entry",
+ IdParseError => "Error while parsing ID"
+ );
+);
+
+pub use self::error::DiaryError;
+pub use self::error::DiaryErrorKind;
+pub use self::error::MapErrInto;
+
diff --git a/lib/domain/libimagdiary/src/is_in_diary.rs b/lib/domain/libimagdiary/src/is_in_diary.rs
new file mode 100644
index 00000000..09228072
--- /dev/null
+++ b/lib/domain/libimagdiary/src/is_in_diary.rs
@@ -0,0 +1,44 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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 libimagstore::store::Entry;
+use libimagstore::storeid::StoreId;
+
+pub trait IsInDiary {
+
+ fn is_in_diary(&self, name: &str) -> bool;
+
+}
+
+impl IsInDiary for Entry {
+
+ fn is_in_diary(&self, name: &str) -> bool {
+ self.get_location().clone().is_in_diary(name)
+ }
+
+}
+
+impl IsInDiary for StoreId {
+
+ fn is_in_diary(&self, name: &str) -> bool {
+ self.local().starts_with(format!("diary/{}", name))
+ }
+
+}
+
diff --git a/lib/domain/libimagdiary/src/iter.rs b/lib/domain/libimagdiary/src/iter.rs
new file mode 100644
index 00000000..de849872
--- /dev/null
+++ b/lib/domain/libimagdiary/src/iter.rs
@@ -0,0 +1,132 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::fmt::{Debug, Formatter, Error as FmtError};
+use std::result::Result as RResult;
+
+use libimagstore::store::Store;
+use libimagstore::storeid::StoreIdIterator;
+
+use diaryid::DiaryId;
+use diaryid::FromStoreId;
+use is_in_diary::IsInDiary;
+use entry::Entry as DiaryEntry;
+use error::DiaryError as DE;
+use error::DiaryErrorKind as DEK;
+use result::Result;
+use libimagerror::trace::trace_error;
+
+/// A iterator for iterating over diary entries
+pub struct DiaryEntryIterator<'a> {
+ store: &'a Store,
+ name: &'a str,
+ iter: StoreIdIterator,
+
+ year: Option<i32>,
+ month: Option<u32>,
+ day: Option<u32>,
+}
+
+impl<'a> Debug for DiaryEntryIterator<'a> {
+
+ fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
+ write!(fmt, "DiaryEntryIterator<name = {}, year = {:?}, month = {:?}, day = {:?}>",
+ self.name, self.year, self.month, self.day)
+ }
+
+}
+
+impl<'a> DiaryEntryIterator<'a> {
+
+ pub fn new(diaryname: &'a str, store: &'a Store, iter: StoreIdIterator) -> DiaryEntryIterator<'a> {
+ DiaryEntryIterator {
+ store: store,
+ name: diaryname,
+ iter: iter,
+
+ year: None,
+ month: None,
+ day: None,
+ }
+ }
+
+ // Filter by year, get all diary entries for this year
+ pub fn year(mut self, year: i32) -> DiaryEntryIterator<'a> {
+ self.year = Some(year);
+ self
+ }
+
+ // Filter by month, get all diary entries for this month (every year)
+ pub fn month(mut self, month: u32) -> DiaryEntryIterator<'a> {
+ self.month = Some(month);
+ self
+ }
+
+ // Filter by day, get all diary entries for this day (every year, every year)
+ pub fn day(mut self, day: u32) -> DiaryEntryIterator<'a> {
+ self.day = Some(day);
+ self
+ }
+
+}
+
+impl<'a> Iterator for DiaryEntryIterator<'a> {
+ type Item = Result<DiaryEntry<'a>>;
+
+ fn next(&mut self) -> Option<Result<DiaryEntry<'a>>> {
+ loop {
+ let next = match self.iter.next() {
+ Some(s) => s,
+ None => return None,
+ };
+ debug!("Next element: {:?}", next);
+
+ if next.is_in_diary(self.name) {
+ debug!("Seems to be in diary: {:?}", next);
+ let id = match DiaryId::from_storeid(&next) {
+ Ok(i) => i,
+ Err(e) => {
+ trace_error(&e);
+ debug!("Couldn't parse {:?} into DiaryId: {:?}", next, e);
+ continue;
+ }
+ };
+ debug!("Success parsing id = {:?}", id);
+
+ let y = match self.year { None => true, Some(y) => y == id.year() };
+ let m = match self.month { None => true, Some(m) => m == id.month() };
+ let d = match self.day { None => true, Some(d) => d == id.day() };
+
+ if y && m && d {
+ debug!("Return = {:?}", id);
+ return Some(self
+ .store
+ .retrieve(next)
+ .map(|fle| DiaryEntry::new(fle))
+ .map_err(|e| DE::new(DEK::StoreReadError, Some(Box::new(e))))
+ );
+ }
+ } else {
+ debug!("Not in the requested diary ({}): {:?}", self.name, next);
+ }
+ }
+ }
+
+}
+
diff --git a/lib/domain/libimagdiary/src/lib.rs b/lib/domain/libimagdiary/src/lib.rs
new file mode 100644
index 00000000..fcabc94e
--- /dev/null
+++ b/lib/domain/libimagdiary/src/lib.rs
@@ -0,0 +1,62 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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
+//
+
+#![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,
+)]
+
+extern crate chrono;
+#[macro_use] extern crate log;
+extern crate semver;
+extern crate toml;
+extern crate toml_query;
+extern crate regex;
+extern crate itertools;
+
+#[macro_use] extern crate libimagstore;
+#[macro_use] extern crate libimagerror;
+extern crate libimagentryedit;
+extern crate libimagentryview;
+extern crate libimagrt;
+extern crate libimagutil;
+
+module_entry_path_mod!("diary");
+
+pub mod config;
+pub mod error;
+pub mod diaryid;
+pub mod diary;
+pub mod is_in_diary;
+pub mod entry;
+pub mod iter;
+pub mod result;
+pub mod viewer;
+
diff --git a/lib/domain/libimagdiary/src/result.rs b/lib/domain/libimagdiary/src/result.rs
new file mode 100644
index 00000000..b4f5f382
--- /dev/null
+++ b/lib/domain/libimagdiary/src/result.rs
@@ -0,0 +1,24 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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 error::DiaryError;
+
+pub type Result<T> = RResult<T, DiaryError>;
diff --git a/lib/domain/libimagdiary/src/viewer.rs b/lib/domain/libimagdiary/src/viewer.rs
new file mode 100644
index 00000000..93b155a7
--- /dev/null
+++ b/lib/domain/libimagdiary/src/viewer.rs
@@ -0,0 +1,64 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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
+//
+
+//! A diary viewer built on libimagentryview.
+
+use entry::Entry;
+use error::DiaryErrorKind as DEK;
+use error::MapErrInto;
+use result::Result;
+
+use libimagentryview::viewer::Viewer;
+use libimagentryview::builtin::plain::PlainViewer;
+
+/// This viewer does _not_ implement libimagentryview::viewer::Viewer because we need to be able to
+/// call some diary-type specific functions on the entries passed to this.
+///
+/// This type is mainly just written to be constructed-called-deleted in one go:
+///
+/// ```ignore
+/// DiaryViewer::new(show_header).view_entries(entries);
+/// ```
+///
+pub struct DiaryViewer(PlainViewer);
+
+impl DiaryViewer {
+
+ pub fn new(show_header: bool) -> DiaryViewer {
+ DiaryViewer(PlainViewer::new(show_header))
+ }
+
+ /// View all entries from the iterator, or stop immediately if an error occurs, returning that
+ /// error.
+ pub fn view_entries<'a, I: Iterator<Item = Entry<'a>>>(&self, entries: I) -> Result<()> {
+ for entry in entries {
+ let id = entry.diary_id();
+ println!("{} :\n", id);
+ let _ = try!(self.0
+ .view_entry(&entry)
+ .map_err_into(DEK::ViewError)
+ .map_err_into(DEK::IOError));
+ println!("\n---\n");
+ }
+
+ Ok(())
+ }
+
+}
+