mylloon.fr/src/routes/cours.rs

149 lines
3.8 KiB
Rust
Raw Normal View History

use std::path::Path;
use actix_web::{get, web, Responder};
use cached::proc_macro::cached;
use ramhorns::Content;
use regex::Regex;
use serde::{Deserialize, Serialize};
use crate::{
config::Config,
misc::{
markdown::{File, TypeFileMetadata},
utils::{make_kw, read_file, Html},
},
template::{Infos, NavBar},
};
#[derive(Debug, Deserialize)]
pub struct PathRequest {
q: Option<String>,
}
2023-04-16 13:18:15 +02:00
#[get("/cours")]
async fn page(info: web::Query<PathRequest>, config: web::Data<Config>) -> impl Responder {
Html(build_page(info, config.get_ref().to_owned()))
}
#[derive(Content, Debug)]
struct CoursTemplate {
navbar: NavBar,
filetree: String,
content: Option<File>,
}
#[derive(Clone, Debug, Serialize)]
struct FileNode {
name: String,
is_dir: bool,
children: Vec<FileNode>,
}
#[cached]
fn compile_patterns(exclusion_list: Vec<String>) -> Vec<Regex> {
exclusion_list
.iter()
.map(|pattern| Regex::new(pattern).unwrap())
.collect()
}
fn get_filetree(dir_path: &str, exclusion_patterns: &Vec<Regex>) -> FileNode {
let children = std::fs::read_dir(dir_path)
.unwrap()
.filter_map(Result::ok)
.filter_map(|entry| {
let entry_path = entry.path();
let entry_name = entry_path.file_name()?.to_string_lossy().to_string();
// Exclude element with the exclusion_list
if exclusion_patterns.iter().any(|re| re.is_match(&entry_name)) {
return None;
}
if entry_path.is_file() {
Some(FileNode {
name: entry_name,
is_dir: false,
children: vec![],
})
} else {
// Exclude empty directories
let children_of_children =
get_filetree(entry_path.to_str().unwrap(), exclusion_patterns);
if children_of_children.is_dir && children_of_children.children.is_empty() {
None
} else {
Some(children_of_children)
}
}
})
.collect();
FileNode {
name: Path::new(dir_path)
.file_name()
.unwrap()
.to_string_lossy()
.to_string(),
is_dir: true,
children,
}
}
/// Get a page content
fn get_content(
cours_dir: &str,
path: &web::Query<PathRequest>,
exclusion_list: Vec<String>,
) -> Option<File> {
let filename = match &path.q {
Some(q) => q,
None => "index.md",
};
// We should support regex?
if exclusion_list
.iter()
.any(|excluded_term| filename.contains(excluded_term.as_str()))
{
return None;
}
read_file(
&format!("{cours_dir}/{filename}"),
TypeFileMetadata::Generic,
)
}
fn build_page(info: web::Query<PathRequest>, config: Config) -> String {
let cours_dir = "data/cours";
let exclusion_list = config.fc.exclude_courses.unwrap();
let exclusion_patterns = compile_patterns(exclusion_list.to_owned());
let filetree = get_filetree(cours_dir, &exclusion_patterns);
config.tmpl.render(
"cours.html",
CoursTemplate {
navbar: NavBar {
cours: true,
..NavBar::default()
},
filetree: serde_json::to_string(&filetree).unwrap(),
content: get_content(cours_dir, &info, exclusion_list),
},
Infos {
page_title: Some("Cours".into()),
page_desc: Some("Cours à l'univ".into()),
page_kw: make_kw(&[
"cours",
"études",
"université",
"licence",
"master",
"notes",
"digital garden",
]),
},
)
2023-04-16 13:18:15 +02:00
}