142 lines
4.2 KiB
Rust
142 lines
4.2 KiB
Rust
use comrak;
|
|
use glob::glob;
|
|
use inflector::Inflector;
|
|
use std::fs::File;
|
|
use std::io::prelude::*;
|
|
use std::path::PathBuf;
|
|
use std::time::SystemTime;
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
/// Structure for representing a wish note
|
|
pub struct Note {
|
|
/// The ID of the note (unique string)
|
|
pub id: String,
|
|
/// The index of the note (unique number)
|
|
pub index: i8,
|
|
/// The raw note data
|
|
pub data: String,
|
|
/// The time the note was last modified
|
|
pub mtime: SystemTime,
|
|
/// The name of the note, i.e. the person it is for
|
|
pub name: String,
|
|
/// The path to the note file
|
|
path: PathBuf,
|
|
}
|
|
|
|
impl Note {
|
|
pub fn to_html(&self) -> String {
|
|
let mut options = comrak::ComrakOptions::default();
|
|
options.ext_strikethrough = true;
|
|
options.ext_tagfilter = true;
|
|
options.ext_autolink = true;
|
|
options.ext_tasklist = true;
|
|
|
|
comrak::markdown_to_html(&self.data, &options)
|
|
}
|
|
|
|
pub fn update_data(&mut self, data: &String) {
|
|
let mut file = File::create(&self.path).expect(&format!(
|
|
"Cannot open note file {}",
|
|
self.path.to_str().unwrap()
|
|
));
|
|
file.write_all(data.as_bytes()).expect(&format!(
|
|
"Cannot write note file {}",
|
|
self.path.to_str().unwrap()
|
|
));
|
|
|
|
self.data = data.clone();
|
|
let metadata = file.metadata().unwrap();
|
|
self.mtime = metadata.modified().unwrap();
|
|
}
|
|
|
|
pub fn load_all(note_path: Option<&str>) -> Vec<Self> {
|
|
let mut notes: Vec<Note> = vec![];
|
|
let mut index = 0;
|
|
let path_glob = match note_path {
|
|
Some(dir) => format!("{}/notes/*.note", dir),
|
|
None => format!("notes/*.note"),
|
|
};
|
|
for entry in glob(path_glob.as_str()).unwrap().filter_map(Result::ok) {
|
|
let file_name = entry.file_name().unwrap().to_str().unwrap();
|
|
let name = match file_name.find('.') {
|
|
Some(index) => &file_name[0..index],
|
|
None => "unknown",
|
|
};
|
|
let mut data = String::new();
|
|
let mut file =
|
|
File::open(&entry).expect(&format!("Cannot open note file {}", file_name));
|
|
file.read_to_string(&mut data)
|
|
.expect(&format!("Cannot read note file {}", file_name));
|
|
let metadata = file.metadata()
|
|
.expect(&format!("Cannot get metadata of note file {}", file_name));
|
|
|
|
let mut note = Note {
|
|
id: String::from(name),
|
|
index: index,
|
|
data: data,
|
|
mtime: metadata.modified().unwrap(),
|
|
name: String::from(name).to_title_case(),
|
|
path: entry.clone(),
|
|
};
|
|
notes.push(note);
|
|
index += 1;
|
|
}
|
|
notes
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn loads_all_notes() {
|
|
let notes = Note::load_all(Some("test"));
|
|
let note_ids: Vec<&str> = notes.iter().map(|note| note.id.as_ref()).collect();
|
|
assert_eq!(note_ids, vec!["test", "updatable"]);
|
|
}
|
|
|
|
#[test]
|
|
fn converts_to_html() {
|
|
let notes = Note::load_all(Some("test"));
|
|
let note = notes.iter().find(|note| note.id == "test").unwrap();
|
|
assert_eq!(
|
|
note.to_html(),
|
|
r#"<p>This is a test list</p>
|
|
<ul>
|
|
<li>One</li>
|
|
<li>Two</li>
|
|
<li>Three</li>
|
|
</ul>
|
|
"#
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn updates_data() {
|
|
let mut notes = Note::load_all(Some("test"));
|
|
let note = notes
|
|
.iter_mut()
|
|
.find(|note| note.id == "updatable")
|
|
.unwrap();
|
|
assert_eq!(note.data, "Some content");
|
|
|
|
// Update the data van verify it has changed
|
|
let new_data = "New content";
|
|
note.update_data(&String::from(new_data));
|
|
assert_eq!(note.data, new_data);
|
|
|
|
// Verify that the data is written to the file of the note by
|
|
// loading them again
|
|
let mut notes = Note::load_all(Some("test"));
|
|
let note = notes
|
|
.iter_mut()
|
|
.find(|note| note.id == "updatable")
|
|
.unwrap();
|
|
assert_eq!(note.data, new_data);
|
|
|
|
// ... and change it back again
|
|
note.update_data(&String::from("Some content"));
|
|
}
|
|
}
|