-
Notifications
You must be signed in to change notification settings - Fork 4
[Added] Now a filebrowser is accessible and attachements can be linked. #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2cacc34
47654a0
481952c
30afb53
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,6 +11,8 @@ extern crate markdown; | |
| extern crate mowl; | ||
| #[macro_use] | ||
| extern crate error_chain; | ||
| #[macro_use] | ||
| extern crate lazy_static; | ||
| extern crate uuid; | ||
| extern crate rayon; | ||
|
|
||
|
|
@@ -25,16 +27,16 @@ use markdown::to_html; | |
| use iron::prelude::*; | ||
| use iron::status; | ||
| use iron::headers::ContentType; | ||
| use iron::mime::Mime; | ||
|
|
||
|
|
||
| use std::fs::{self, canonicalize, create_dir_all, File}; | ||
| use std::fs::{self, canonicalize, create_dir_all, File, OpenOptions}; | ||
| use std::path::{Path, PathBuf, MAIN_SEPARATOR}; | ||
| use std::io::prelude::*; | ||
| use std::str; | ||
| use filehash::Filehash; | ||
| use rayon::iter::{ParallelIterator, IntoParallelRefMutIterator}; | ||
|
|
||
| static SHA_FILE: &str = ".files.sha"; | ||
|
|
||
| pub struct InputPaths { | ||
| path: PathBuf, | ||
| hash: String, | ||
|
|
@@ -114,6 +116,21 @@ impl InputPaths { | |
| } | ||
| } | ||
|
|
||
| lazy_static! { | ||
| static ref PDF_MIME: Mime = "application/pdf".parse::<Mime>().unwrap(); | ||
| static ref DOC_MIME: Mime = "application/msword".parse::<Mime>().unwrap(); | ||
| static ref ODA_MIME: Mime = "application/oda".parse::<Mime>().unwrap(); | ||
| static ref ZIP_MIME: Mime = "application/zip".parse::<Mime>().unwrap(); | ||
| static ref WAV_MIME: Mime = "audio/x-wav".parse::<Mime>().unwrap(); | ||
| static ref CSS_MIME: Mime = "text/css".parse::<Mime>().unwrap(); | ||
| static ref GIF_MIME: Mime = "image/gif".parse::<Mime>().unwrap(); | ||
| static ref MPG_MIME: Mime = "video/mpeg".parse::<Mime>().unwrap(); | ||
| static ref AVI_MIME: Mime = "video/x-msvideo".parse::<Mime>().unwrap(); | ||
| static ref PNG_MIME: Mime = "image/png".parse::<Mime>().unwrap(); | ||
| static ref JPG_MIME: Mime = "image/jpeg".parse::<Mime>().unwrap(); | ||
| static ref SHA_FILE: &'static str = ".files.sha"; | ||
| } | ||
|
|
||
| #[derive(Default)] | ||
| /// Global processing structure | ||
| pub struct Wiki { | ||
|
|
@@ -139,7 +156,6 @@ impl Wiki { | |
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Reads all markdown files recursively from a given directory. | ||
| /// Clears the current available input_paths | ||
| pub fn read_from_directory(&mut self, directory: &str) -> Result<()> { | ||
|
|
@@ -161,7 +177,6 @@ impl Wiki { | |
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Print absolute path of all added md files | ||
| pub fn list_current_input_paths(&self) { | ||
| info!("Found the following markdown files:"); | ||
|
|
@@ -184,7 +199,7 @@ impl Wiki { | |
| fs::create_dir(output_directory)?; | ||
| } | ||
|
|
||
| let sha_file_path = PathBuf::from(output_directory).join(SHA_FILE); | ||
| let sha_file_path = PathBuf::from(output_directory).join(*SHA_FILE); | ||
| let sha_file = sha_file_path.to_str() | ||
| .ok_or_else(|| "Unable to stringify the sha file path.")?; | ||
|
|
||
|
|
@@ -225,20 +240,92 @@ impl Wiki { | |
| Ok(()) | ||
| } | ||
|
|
||
| /// Add a directory for storing files to the generated html sites or read stored | ||
| /// files of existing filestorage. Afterwards file links will be added to the | ||
| /// generated html site. | ||
| pub fn read_files(&mut self, file_folder: &str, output: &str) -> Result<()> { | ||
|
|
||
| //create the default file path | ||
| let output_path = PathBuf::from(output); | ||
| let file_directory = PathBuf::from(output).join(file_folder); | ||
|
|
||
| if !Path::new(file_folder).exists(){ | ||
| info!("Creating directory for file input: {:?}.", file_directory.to_str()); | ||
| fs::create_dir(&file_directory); | ||
| } | ||
|
|
||
| for path in &self.input_paths{ | ||
| let mut count = 0; | ||
|
|
||
| //create the path for the html site or just find it | ||
| let page_files_path = file_directory.join(&path.path).to_str().ok_or_else(|| | ||
| "Couldn't create Path to html file!")?.replace(".md",""); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This error message is a bit weird. It would be also better to break the lines here for better reading. |
||
|
|
||
| if !PathBuf::from(page_files_path.as_str()).exists(){ | ||
| info!("Creating directory for {}'s files: {}.", path.path.to_str().ok_or_else(|| "Path not found!")?, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be good when specifying which path can't be found. For this we should rework the error messages for the whole project, there are much things in like this ^^ |
||
| page_files_path.as_str()); | ||
| fs::create_dir_all(page_files_path.as_str()); | ||
| } | ||
|
|
||
| //add the path | ||
| let file_path = Path::new(page_files_path.as_str()); | ||
| //read all the files | ||
| let files = file_path.read_dir()?; | ||
|
|
||
| //now attach the files to the html sites folder | ||
| for entry in files { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here you can get rid of the extra var but write |
||
| let current_entry = match entry { | ||
| Ok(entry) => entry, | ||
| _ => panic!("Couldn't read the path!"), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better return an error with a meaningful description here. |
||
| }; | ||
|
|
||
| let link = format!( | ||
| "\n<a href='http://localhost:30000/files/{}/{}'>{}</a><br>\n", | ||
| path.path.to_str().ok_or_else(|| "Path not found!")?.replace(".md", ""), | ||
| current_entry.file_name().to_str().ok_or_else(|| "Entry is corrupted!")?.replace("\n","."), | ||
| current_entry.file_name().to_str().ok_or_else(|| "Entry is corrupted!")? | ||
| ); | ||
| let mut html_file = OpenOptions::new().read(true).write(true).create(true). | ||
| open(output_path.join(&path.path).to_str().ok_or_else(|| "Entry is corrupted!")?. | ||
| replace(".md", ".html"))?; | ||
|
|
||
| let mut buffer = String::new(); | ||
|
|
||
| html_file.read_to_string(&mut buffer); | ||
| buffer += &link.as_str(); | ||
| info!("Creating link to {:?} for {:?}", current_entry.file_name(), path.path.to_str() | ||
| .ok_or_else(|| "Entry is corrupted!")?.replace(".md", ".html")); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| html_file.write((&buffer).as_bytes()); | ||
| count += 1; | ||
| } | ||
| //check if there are no files attached | ||
| if count == 0 { | ||
| info!("No files found so far for {}. Simply add your files to the folders in 'files'.", | ||
| path.path.to_str().ok_or_else(|| "Entry is corrupted!")?) | ||
| } | ||
| } | ||
| Ok(()) | ||
| } | ||
|
|
||
| /// Create an HTTP server serving the generated files | ||
| pub fn serve(&self, output_directory: &str) -> Result<()> { | ||
|
|
||
| // Create a default listening address | ||
| let addr = "localhost:5000"; | ||
| let addr = "localhost:30000"; | ||
| info!("Listening on {}", addr); | ||
|
|
||
| // Moving the data into the closure | ||
| let output_directory_string = output_directory.to_owned(); | ||
|
|
||
| // Create a new iron instance | ||
| Iron::new(move |request: &mut Request| { | ||
| // The owned path needs to created from the cloned string | ||
| let mut path = PathBuf::from(output_directory_string.clone()); | ||
|
|
||
| ///to load files in browser | ||
| fn get_file(mime_type: &Mime, body: File) -> iron::Response { | ||
| let mut resp = Response::with((status::Ok, body)); | ||
| resp.headers.set(ContentType(mime_type.to_owned())); | ||
| resp | ||
| } | ||
| let mut path = PathBuf::from(&output_directory_string); | ||
| // Create the full path | ||
| for part in request.url.path() { | ||
| path.push(part); | ||
|
|
@@ -251,27 +338,48 @@ impl Wiki { | |
| path.push("index.html"); | ||
| } | ||
|
|
||
| let mut f = match File::open(path) { | ||
| if !path.exists() { | ||
| return Ok(Response::with((ContentType::html().0, | ||
| status::NotFound, include_str!("html/404.html")))); | ||
| } | ||
| let mut f = match File::open(&path) { | ||
| Ok(v) => v, | ||
| _ => return Ok(Response::with((ContentType::html().0, | ||
| status::NotFound, | ||
| include_str!("html/404.html")))), | ||
| }; | ||
|
|
||
| let mut buffer = String::new(); | ||
| match f.read_to_string(&mut buffer) { | ||
| Ok(v) => v, | ||
| _ => return Ok(Response::with((ContentType::html().0, | ||
| status::InternalServerError, | ||
| include_str!("html/500.html")))), | ||
| }; | ||
|
|
||
| // Content type needs to be determined from the file rather | ||
| // than assuming html | ||
| Ok(Response::with((ContentType::html().0, status::Ok, buffer))) | ||
|
|
||
| }; | ||
|
|
||
| match path.to_str(){ | ||
| Some(name) => { | ||
|
|
||
| if name.contains(".pdf") {return Ok(get_file(&(*PDF_MIME), f))}; | ||
| if name.contains(".doc") {return Ok(get_file(&(*DOC_MIME), f))}; | ||
| if name.contains(".oda") {return Ok(get_file(&(*ODA_MIME), f))}; | ||
| if name.contains(".zip") {return Ok(get_file(&(*ZIP_MIME), f))}; | ||
| if name.contains(".wav") {return Ok(get_file(&(*WAV_MIME), f))}; | ||
| if name.contains(".css") {return Ok(get_file(&(*CSS_MIME), f))}; | ||
| if name.contains(".mp") {return Ok(get_file(&(*MPG_MIME), f))}; | ||
| if name.contains(".avi") {return Ok(get_file(&(*AVI_MIME), f))}; | ||
| if name.contains(".png") {return Ok(get_file(&(*PNG_MIME), f))}; | ||
| if name.contains(".jp") {return Ok(get_file(&(*JPG_MIME), f))}; | ||
| if name.contains(".gif") {return Ok(get_file(&(*GIF_MIME), f))}; | ||
|
|
||
| if name.contains(".html") { | ||
| let mut buffer = String::new(); | ||
| match f.read_to_string(&mut buffer) { | ||
| Ok(v) => v, | ||
| _ => return Ok(Response::with((ContentType::html().0, | ||
| status::InternalServerError, | ||
| include_str!("html/500.html")))), | ||
| }; | ||
| return Ok(Response::with((ContentType::html().0, status::Ok, buffer))) | ||
| } | ||
|
|
||
| else {Ok(Response::with((status::Ok, f)))} | ||
| }, | ||
| _ => panic!("Invalid Path."), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here also return an Error. |
||
| } | ||
| }).http(addr)?; | ||
|
|
||
| Ok(()) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since input and output directory we have now additionally a file directory and as a user I would have no idea wherefore this is and the description is not really helpful.