diff options
Diffstat (limited to 'lib/domain/libimagwiki/src')
-rw-r--r-- | lib/domain/libimagwiki/src/entry.rs | 73 | ||||
-rw-r--r-- | lib/domain/libimagwiki/src/error.rs | 55 | ||||
-rw-r--r-- | lib/domain/libimagwiki/src/lib.rs | 55 | ||||
-rw-r--r-- | lib/domain/libimagwiki/src/store.rs | 84 | ||||
-rw-r--r-- | lib/domain/libimagwiki/src/wiki.rs | 144 |
5 files changed, 411 insertions, 0 deletions
diff --git a/lib/domain/libimagwiki/src/entry.rs b/lib/domain/libimagwiki/src/entry.rs new file mode 100644 index 00000000..39b9d805 --- /dev/null +++ b/lib/domain/libimagwiki/src/entry.rs @@ -0,0 +1,73 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 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::Store; +use libimagstore::store::Entry; +use libimagentrymarkdown::processor::LinkProcessor; + +use error::Result; +use error::WikiErrorKind as WEK; +use error::ResultExt; + +pub trait WikiEntry { + fn autolink(&mut self, store: &Store) -> Result<()>; + fn autolink_with_processor(&mut self, store: &Store, processor: LinkProcessor) -> Result<()>; +} + +impl WikiEntry for Entry { + + /// Autolink entry to entries linked in content + /// + /// Uses `libimagentrymarkdown::processor::LinkProcessor` for this, with the following settings: + /// + /// * Interal link processing = true + /// * Internal targets creating = true + /// * External link processing = true + /// * Processing of Refs = true + /// + /// This is a convenience function for `WikiEntry::autolink_with_processor()`. + /// + /// # Warning + /// + /// With this function, the `LinkProcessor` automatically creates entries in the store if they + /// are linked from the current entry but do not exists yet. + /// + /// # See also + /// + /// * The documentation of `WikiEntry::autolink_with_processor()`. + /// * The documentation of `::libimagentrymarkdown::processor::LinkProcessor`. + /// + fn autolink(&mut self, store: &Store) -> Result<()> { + let processor = LinkProcessor::default() + .process_internal_links(true) + .create_internal_targets(true) + .process_external_links(true) + .process_refs(true); + + self.autolink_with_processor(store, processor) + } + + /// Autolink entry to entries linked in content with the passed `LinkProcessor` instance. + /// + /// See the documentation of `::libimagentrymarkdown::processor::LinkProcessor`. + fn autolink_with_processor(&mut self, store: &Store, processor: LinkProcessor) -> Result<()> { + processor.process(self, store).chain_err(|| WEK::AutoLinkError(self.get_location().clone())) + } + +} diff --git a/lib/domain/libimagwiki/src/error.rs b/lib/domain/libimagwiki/src/error.rs new file mode 100644 index 00000000..185f71f8 --- /dev/null +++ b/lib/domain/libimagwiki/src/error.rs @@ -0,0 +1,55 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 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::storeid::StoreId; + +error_chain! { + types { + WikiError, WikiErrorKind, ResultExt, Result; + } + + links { + StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind); + LinkError(::libimagentrylink::error::LinkError, ::libimagentrylink::error::LinkErrorKind); + } + + errors { + WikiDoesNotExist(name: String) { + description("Wiki does not exist") + display("Wiki '{}' does not exist", name) + } + + WikiExists(name: String) { + description("Wiki exist already") + display("Wiki '{}' exists already", name) + } + + AutoLinkError(sid: StoreId) { + description("Error while autolinking entry") + display("Error while autolinking entry: {}", sid) + } + + MissingIndex { + description("Index page for wiki is missing") + display("Index page for wiki is missing") + } + } + +} + diff --git a/lib/domain/libimagwiki/src/lib.rs b/lib/domain/libimagwiki/src/lib.rs new file mode 100644 index 00000000..ef1801c1 --- /dev/null +++ b/lib/domain/libimagwiki/src/lib.rs @@ -0,0 +1,55 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 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 +// + +#![recursion_limit="256"] + +#![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 filters; +extern crate toml; +extern crate toml_query; +#[macro_use] extern crate log; +#[macro_use] extern crate error_chain; + +#[macro_use] extern crate libimagstore; +extern crate libimagerror; +extern crate libimagentrylink; +extern crate libimagentrymarkdown; + +module_entry_path_mod!("wiki"); + +pub mod entry; +pub mod error; +pub mod store; +pub mod wiki; + diff --git a/lib/domain/libimagwiki/src/store.rs b/lib/domain/libimagwiki/src/store.rs new file mode 100644 index 00000000..7113aa17 --- /dev/null +++ b/lib/domain/libimagwiki/src/store.rs @@ -0,0 +1,84 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 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::Store; +use libimagstore::storeid::StoreId; +use libimagstore::storeid::IntoStoreId; + +use error::WikiError as WE; +use error::Result; +use wiki::Wiki; + +pub trait WikiStore { + + fn get_wiki<'a, 'b>(&'a self, name: &'b str) -> Result<Option<Wiki<'a, 'b>>>; + + fn create_wiki<'a, 'b>(&'a self, name: &'b str) + -> Result<Wiki<'a, 'b>>; + + fn retrieve_wiki<'a, 'b>(&'a self, name: &'b str) + -> Result<Wiki<'a, 'b>>; + +} + +impl WikiStore for Store { + + /// get a wiki by its name + fn get_wiki<'a, 'b>(&'a self, name: &'b str) -> Result<Option<Wiki<'a, 'b>>> { + if wiki_path(name.as_ref())?.with_base(self.path().clone()).exists()? { + debug!("Building Wiki object"); + Ok(Some(Wiki::new(self, name))) + } else { + debug!("Cannot build wiki object: Wiki does not exist"); + Ok(None) + } + } + + /// Create a wiki. + /// + /// # Returns + /// + /// Returns the Wiki object. + /// + /// Ob success, an empty Wiki entry with the name `index` is created inside the wiki. Later, new + /// entries are automatically linked to this entry. + /// + fn create_wiki<'a, 'b>(&'a self, name: &'b str) -> Result<Wiki<'a, 'b>> { + debug!("Trying to get wiki '{}'", name); + + let wiki = Wiki::new(self, name); + let _ = wiki.create_index_page()?; + Ok(wiki) + } + + fn retrieve_wiki<'a, 'b>(&'a self, name: &'b str) + -> Result<Wiki<'a, 'b>> + { + match self.get_wiki(name)? { + None => self.create_wiki(name), + Some(wiki) => Ok(wiki), + } + } + +} + +fn wiki_path(name: &str) -> Result<StoreId> { + ::module_path::ModuleEntryPath::new(name).into_storeid().map_err(WE::from) +} + diff --git a/lib/domain/libimagwiki/src/wiki.rs b/lib/domain/libimagwiki/src/wiki.rs new file mode 100644 index 00000000..50ef61cd --- /dev/null +++ b/lib/domain/libimagwiki/src/wiki.rs @@ -0,0 +1,144 @@ +// +// imag - the personal information management suite for the commandline +// Copyright (C) 2015-2018 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::path::PathBuf; + +use filters::filter::Filter; + +use libimagstore::store::Store; +use libimagstore::store::Entry; +use libimagstore::store::FileLockEntry; +use libimagstore::storeid::IntoStoreId; +use libimagstore::storeid::StoreId; +use libimagstore::storeid::StoreIdIteratorWithStore; +use libimagentrylink::internal::InternalLinker; + +use error::WikiError as WE; +use error::WikiErrorKind as WEK; +use error::Result; + +pub struct Wiki<'a, 'b>(&'a Store, &'b str); + +/// An interface for accessing, creating and deleting "wiki pages" +/// +/// Wiki pages are normal entries with some details added. +/// +/// +/// # Details +/// +/// Entries are automatically linked to the "index" page when created and retrieved. +/// +impl<'a, 'b> Wiki<'a, 'b> { + + pub(crate) fn new(store: &'a Store, name: &'b str) -> Wiki<'a, 'b> { + Wiki(store, name) + } + + pub(crate) fn create_index_page(&self) -> Result<FileLockEntry<'a>> { + let path = PathBuf::from(format!("{}/index", self.1)); + let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?; + + self.0 + .create(sid) + .map_err(WE::from) + } + + pub fn get_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<Option<FileLockEntry<'a>>> { + let path = PathBuf::from(format!("{}/{}", self.1, entry_name.as_ref())); + let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?; + self.0.get(sid).map_err(WE::from) + } + + pub fn create_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<FileLockEntry<'a>> { + let path = PathBuf::from(format!("{}/{}", self.1, entry_name.as_ref())); + let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?; + let mut index = self + .get_entry("index")? + .ok_or_else(|| WEK::MissingIndex.into()) + .map_err(WE::from_kind)?; + let mut entry = self.0.create(sid)?; + + entry.add_internal_link(&mut index) + .map_err(WE::from) + .map(|_| entry) + } + + pub fn retrieve_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<FileLockEntry<'a>> { + let path = PathBuf::from(format!("{}/{}", self.1, entry_name.as_ref())); + let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?; + let mut index = self + .get_entry("index")? + .ok_or_else(|| WEK::MissingIndex.into()) + .map_err(WE::from_kind)?; + let mut entry = self.0.retrieve(sid)?; + + entry.add_internal_link(&mut index) + .map_err(WE::from) + .map(|_| entry) + } + + pub fn all_ids(&self) -> Result<WikiIdIterator> { + let filter = IdIsInWikiFilter(self.1); + Ok(WikiIdIterator(self.0.entries()?, filter)) + } + + pub fn delete_entry<EN: AsRef<str>>(&self, entry_name: EN) -> Result<()> { + let path = PathBuf::from(format!("{}/{}", self.1, entry_name.as_ref())); + let sid = ::module_path::ModuleEntryPath::new(path).into_storeid()?; + self.0.delete(sid).map_err(WE::from) + } +} + +pub struct WikiIdIterator<'a>(StoreIdIteratorWithStore<'a>, IdIsInWikiFilter<'a>); + +impl<'a> Iterator for WikiIdIterator<'a> { + type Item = StoreId; + + fn next(&mut self) -> Option<Self::Item> { + while let Some(next) = self.0.next() { + if self.1.filter(&next) { + return Some(next) + } + } + + None + } +} + +pub struct IdIsInWikiFilter<'a>(&'a str); + +impl<'a> IdIsInWikiFilter<'a> { + pub fn new(wiki_name: &'a str) -> Self { + IdIsInWikiFilter(wiki_name) + } +} + +impl<'a> Filter<StoreId> for IdIsInWikiFilter<'a> { + fn filter(&self, id: &StoreId) -> bool { + id.is_in_collection(&["wiki", &self.0]) + } +} + +impl<'a> Filter<Entry> for IdIsInWikiFilter<'a> { + fn filter(&self, e: &Entry) -> bool { + e.get_location().is_in_collection(&["wiki", &self.0]) + } +} + + |