This commit is contained in:
parent
0d924de79b
commit
aba8a501af
8 changed files with 87 additions and 99 deletions
|
@ -31,3 +31,11 @@ base64 = "0.22"
|
||||||
mime_guess = "2.0"
|
mime_guess = "2.0"
|
||||||
urlencoding = "2.1"
|
urlencoding = "2.1"
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
correctness = "warn"
|
||||||
|
suspicious = "warn"
|
||||||
|
complexity = "warn"
|
||||||
|
perf = "warn"
|
||||||
|
style = "warn"
|
||||||
|
pedantic = "warn"
|
||||||
|
|
|
@ -40,14 +40,14 @@ impl FileConfiguration {
|
||||||
port: Some(8080),
|
port: Some(8080),
|
||||||
app_name: Some("EWP".into()),
|
app_name: Some("EWP".into()),
|
||||||
exclude_courses: Some([].into()),
|
exclude_courses: Some([].into()),
|
||||||
..FileConfiguration::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete default structure with an existing one
|
/// Complete default structure with an existing one
|
||||||
fn complete(a: Self) -> Self {
|
fn complete(a: Self) -> Self {
|
||||||
// Default config
|
// Default config
|
||||||
let d = FileConfiguration::new();
|
let d = Self::new();
|
||||||
|
|
||||||
#[allow(clippy::items_after_statements)]
|
#[allow(clippy::items_after_statements)]
|
||||||
/// Return the default value if nothing is value is none
|
/// Return the default value if nothing is value is none
|
||||||
|
@ -94,18 +94,15 @@ pub struct Config {
|
||||||
|
|
||||||
/// Load the config file
|
/// Load the config file
|
||||||
fn get_file_config(file_path: &str) -> FileConfiguration {
|
fn get_file_config(file_path: &str) -> FileConfiguration {
|
||||||
match fs::read_to_string(file_path) {
|
fs::read_to_string(file_path).map_or_else(
|
||||||
Ok(file) => match toml::from_str(&file) {
|
|_| FileConfiguration::new(),
|
||||||
|
|file| match toml::from_str(&file) {
|
||||||
Ok(stored_config) => FileConfiguration::complete(stored_config),
|
Ok(stored_config) => FileConfiguration::complete(stored_config),
|
||||||
Err(file_error) => {
|
Err(file_error) => {
|
||||||
panic!("Error in config file: {file_error}");
|
panic!("Error in config file: {file_error}");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(_) => {
|
)
|
||||||
// No config file
|
|
||||||
FileConfiguration::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the configuration
|
/// Build the configuration
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use core::panic;
|
|
||||||
|
|
||||||
use reqwest::{header::ACCEPT, Error};
|
use reqwest::{header::ACCEPT, Error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
@ -32,13 +30,15 @@ pub enum ProjectState {
|
||||||
Merged = 2,
|
Merged = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for ProjectState {
|
impl TryFrom<u8> for ProjectState {
|
||||||
fn from(orig: u8) -> Self {
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(orig: u8) -> Result<Self, Self::Error> {
|
||||||
match orig {
|
match orig {
|
||||||
0 => Self::Closed,
|
0 => Ok(Self::Closed),
|
||||||
1 => Self::Open,
|
1 => Ok(Self::Open),
|
||||||
2 => Self::Merged,
|
2 => Ok(Self::Merged),
|
||||||
_ => panic!(),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,7 +106,7 @@ pub struct Metadata {
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
/// Update current metadata boolean fields, keeping true ones
|
/// Update current metadata boolean fields, keeping true ones
|
||||||
fn merge(&mut self, other: &Metadata) {
|
fn merge(&mut self, other: &Self) {
|
||||||
self.math = self.math || other.math;
|
self.math = self.math || other.math;
|
||||||
self.mermaid = self.mermaid || other.mermaid;
|
self.mermaid = self.mermaid || other.mermaid;
|
||||||
self.syntax_highlight = self.syntax_highlight || other.syntax_highlight;
|
self.syntax_highlight = self.syntax_highlight || other.syntax_highlight;
|
||||||
|
@ -268,10 +268,7 @@ pub fn read_md(
|
||||||
) -> File {
|
) -> File {
|
||||||
let arena = Arena::new();
|
let arena = Arena::new();
|
||||||
|
|
||||||
let opt = match options {
|
let opt = options.map_or_else(get_options, |specific_opt| specific_opt);
|
||||||
Some(specific_opt) => specific_opt,
|
|
||||||
None => get_options(),
|
|
||||||
};
|
|
||||||
let root = parse_document(&arena, raw_text, &opt);
|
let root = parse_document(&arena, raw_text, &opt);
|
||||||
|
|
||||||
// Find metadata
|
// Find metadata
|
||||||
|
@ -314,8 +311,7 @@ fn deserialize_metadata<T: Default + serde::de::DeserializeOwned>(text: &str) ->
|
||||||
|
|
||||||
/// Fetch metadata from AST
|
/// Fetch metadata from AST
|
||||||
pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> FileMetadata {
|
pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> FileMetadata {
|
||||||
match root
|
root.children()
|
||||||
.children()
|
|
||||||
.find_map(|node| match &node.data.borrow().value {
|
.find_map(|node| match &node.data.borrow().value {
|
||||||
// Extract metadata from frontmatter
|
// Extract metadata from frontmatter
|
||||||
NodeValue::FrontMatter(text) => Some(match mtype {
|
NodeValue::FrontMatter(text) => Some(match mtype {
|
||||||
|
@ -336,9 +332,7 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeFileMetadata::Generic => FileMetadata {
|
TypeFileMetadata::Generic => FileMetadata::default(),
|
||||||
..FileMetadata::default()
|
|
||||||
},
|
|
||||||
TypeFileMetadata::Index => FileMetadata {
|
TypeFileMetadata::Index => FileMetadata {
|
||||||
index: Some(deserialize_metadata(text)),
|
index: Some(deserialize_metadata(text)),
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
|
@ -349,10 +343,9 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}) {
|
})
|
||||||
Some(data) => data,
|
.map_or_else(
|
||||||
// No metadata
|
|| match mtype {
|
||||||
None => match mtype {
|
|
||||||
TypeFileMetadata::Blog => FileMetadata {
|
TypeFileMetadata::Blog => FileMetadata {
|
||||||
blog: Some(FileMetadataBlog::default()),
|
blog: Some(FileMetadataBlog::default()),
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
|
@ -361,9 +354,7 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File
|
||||||
contact: Some(FileMetadataContact::default()),
|
contact: Some(FileMetadataContact::default()),
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
},
|
},
|
||||||
TypeFileMetadata::Generic => FileMetadata {
|
TypeFileMetadata::Generic => FileMetadata::default(),
|
||||||
..FileMetadata::default()
|
|
||||||
},
|
|
||||||
TypeFileMetadata::Index => FileMetadata {
|
TypeFileMetadata::Index => FileMetadata {
|
||||||
index: Some(FileMetadataIndex::default()),
|
index: Some(FileMetadataIndex::default()),
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
|
@ -373,7 +364,8 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
|data| data,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether mermaid diagrams are in the AST
|
/// Check whether mermaid diagrams are in the AST
|
||||||
|
|
|
@ -54,19 +54,14 @@ impl Responder for Html {
|
||||||
|
|
||||||
/// Read a file
|
/// Read a file
|
||||||
pub fn read_file(filename: &str, expected_file: &TypeFileMetadata) -> Option<File> {
|
pub fn read_file(filename: &str, expected_file: &TypeFileMetadata) -> Option<File> {
|
||||||
match Path::new(filename).extension() {
|
Path::new(filename)
|
||||||
Some(ext) => match ext.to_str().unwrap() {
|
.extension()
|
||||||
"pdf" => match fs::read(filename) {
|
.and_then(|ext| match ext.to_str().unwrap() {
|
||||||
Ok(bytes) => Some(read_pdf(bytes)),
|
"pdf" => fs::read(filename).map_or(None, |bytes| Some(read_pdf(bytes))),
|
||||||
Err(_) => None,
|
_ => fs::read_to_string(filename).map_or(None, |text| {
|
||||||
},
|
Some(read_md(filename, &text, expected_file, None))
|
||||||
_ => match fs::read_to_string(filename) {
|
}),
|
||||||
Ok(text) => Some(read_md(filename, &text, expected_file, None)),
|
})
|
||||||
Err(_) => None,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_pdf(data: Vec<u8>) -> File {
|
fn read_pdf(data: Vec<u8>) -> File {
|
||||||
|
|
|
@ -110,16 +110,14 @@ impl Hash for Post {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_posts(location: &str) -> Vec<Post> {
|
fn get_posts(location: &str) -> Vec<Post> {
|
||||||
let entries = match std::fs::read_dir(location) {
|
let entries = std::fs::read_dir(location).map_or_else(
|
||||||
Ok(res) => res
|
|_| vec![],
|
||||||
.flatten()
|
|res| {
|
||||||
.filter(|f| match f.path().extension() {
|
res.flatten()
|
||||||
Some(ext) => ext == "md",
|
.filter(|f| f.path().extension().map_or(false, |ext| ext == "md"))
|
||||||
None => false,
|
.collect::<Vec<std::fs::DirEntry>>()
|
||||||
})
|
},
|
||||||
.collect::<Vec<std::fs::DirEntry>>(),
|
);
|
||||||
Err(_) => vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
entries
|
entries
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -128,36 +126,37 @@ fn get_posts(location: &str) -> Vec<Post> {
|
||||||
let filename = fname.to_string_lossy();
|
let filename = fname.to_string_lossy();
|
||||||
let file_without_ext = filename.split_at(filename.len() - 3).0;
|
let file_without_ext = filename.split_at(filename.len() - 3).0;
|
||||||
|
|
||||||
let file_metadata = match std::fs::read_to_string(format!("{location}/{filename}")) {
|
let file_metadata = std::fs::read_to_string(format!("{location}/{filename}"))
|
||||||
Ok(text) => {
|
.map_or_else(
|
||||||
|
|_| FileMetadataBlog {
|
||||||
|
title: Some(file_without_ext.into()),
|
||||||
|
..FileMetadataBlog::default()
|
||||||
|
},
|
||||||
|
|text| {
|
||||||
let arena = Arena::new();
|
let arena = Arena::new();
|
||||||
|
|
||||||
let options = get_options();
|
let options = get_options();
|
||||||
let root = parse_document(&arena, &text, &options);
|
let root = parse_document(&arena, &text, &options);
|
||||||
let mut metadata = get_metadata(root, &TypeFileMetadata::Blog).blog.unwrap();
|
let mut metadata =
|
||||||
|
get_metadata(root, &TypeFileMetadata::Blog).blog.unwrap();
|
||||||
|
|
||||||
// Always have a title
|
// Always have a title
|
||||||
metadata.title = match metadata.title {
|
metadata.title = metadata
|
||||||
Some(title) => Some(title),
|
.title
|
||||||
None => Some(file_without_ext.into()),
|
.map_or_else(|| Some(file_without_ext.into()), Some);
|
||||||
};
|
|
||||||
|
|
||||||
metadata
|
metadata
|
||||||
}
|
|
||||||
Err(_) => FileMetadataBlog {
|
|
||||||
title: Some(file_without_ext.into()),
|
|
||||||
..FileMetadataBlog::default()
|
|
||||||
},
|
},
|
||||||
};
|
);
|
||||||
|
|
||||||
if let Some(true) = file_metadata.publish {
|
if file_metadata.publish == Some(true) {
|
||||||
Some(Post {
|
Some(Post {
|
||||||
url: file_without_ext.into(),
|
url: file_without_ext.into(),
|
||||||
title: file_metadata.title.unwrap(),
|
title: file_metadata.title.unwrap(),
|
||||||
date: file_metadata.date.unwrap_or({
|
date: file_metadata.date.unwrap_or({
|
||||||
let m = f.metadata().unwrap();
|
let m = f.metadata().unwrap();
|
||||||
let date = std::convert::Into::<DateTime<Utc>>::into(
|
let date = std::convert::Into::<DateTime<Utc>>::into(
|
||||||
m.modified().unwrap_or(m.created().unwrap()),
|
m.modified().unwrap_or_else(|_| m.created().unwrap()),
|
||||||
)
|
)
|
||||||
.date_naive();
|
.date_naive();
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ async fn build_page(config: Config) -> String {
|
||||||
// Distributes each PR in the right vector
|
// Distributes each PR in the right vector
|
||||||
for d in &mut data {
|
for d in &mut data {
|
||||||
map.get(d.name.as_str()).unwrap().iter().for_each(|p| {
|
map.get(d.name.as_str()).unwrap().iter().for_each(|p| {
|
||||||
let state = p.state.into();
|
let state = p.state.try_into().unwrap();
|
||||||
match state {
|
match state {
|
||||||
ProjectState::Closed => d.pulls_closed.push(p.to_owned()),
|
ProjectState::Closed => d.pulls_closed.push(p.to_owned()),
|
||||||
ProjectState::Merged => d.pulls_merged.push(p.to_owned()),
|
ProjectState::Merged => d.pulls_merged.push(p.to_owned()),
|
||||||
|
|
|
@ -96,10 +96,7 @@ fn get_content(
|
||||||
path: &web::Query<PathRequest>,
|
path: &web::Query<PathRequest>,
|
||||||
exclusion_list: &[String],
|
exclusion_list: &[String],
|
||||||
) -> Option<File> {
|
) -> Option<File> {
|
||||||
let filename = match &path.q {
|
let filename = path.q.as_ref().map_or("index.md", |q| q);
|
||||||
Some(q) => q,
|
|
||||||
None => "index.md",
|
|
||||||
};
|
|
||||||
|
|
||||||
// We should support regex?
|
// We should support regex?
|
||||||
if exclusion_list
|
if exclusion_list
|
||||||
|
|
Loading…
Reference in a new issue