Skip to content
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

Render page 404 #71

Merged
merged 8 commits into from
Oct 23, 2024
Merged
5 changes: 5 additions & 0 deletions example/content/404.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
title: Page not found
---

Page not found :/
2 changes: 1 addition & 1 deletion example/templates/base.html
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ <h2><a href="{{url_for(path='/')}}" class="contrast">{{ site.name }}</a></h2>
<ul class="header-menu" id="header-menu">
{% for item in menu %}
<li>
{% if current_page == item.1 %}
{% if current_page and current_page == item.1 %}
<button class="secondary">{{item.0 | safe }}</button>
{% else %}
<a href="{{ url_for(path=item.1) }}" class="secondary" {%if item.1 is starting_with("http") %}target="_blank"{% endif %}>{{ item.0 | safe }}</a>
19 changes: 17 additions & 2 deletions src/markdown.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,11 @@ use frontmatter_gen::{extract, Frontmatter};
use std::fs;
use std::path::Path;

pub fn process_file(path: &Path, site_data: &mut Data) -> Result<(), String> {
pub fn process_file(
path: &Path,
site_data: &mut Data,
use_filename_as_slug: bool,
) -> Result<(), String> {
let file_content = fs::read_to_string(path).map_err(|e| e.to_string())?;
let (frontmatter, markdown) = parse_front_matter(&file_content)?;
let mut options = ComrakOptions::default();
@@ -39,7 +43,18 @@ pub fn process_file(path: &Path, site_data: &mut Data) -> Result<(), String> {

let title = get_title(&frontmatter, markdown);
let tags = get_tags(&frontmatter);
let slug = get_slug(&frontmatter, path);
let slug = {
if use_filename_as_slug {
path.file_name()
.expect("Error on getting file name")
.to_str()
.expect("Error on converting file name to string")
.to_string()
.replace(".md", "")
} else {
get_slug(&frontmatter, path)
}
};
let date = get_date(&frontmatter, path);

let extra = frontmatter.get("extra").map(std::borrow::ToOwned::to_owned);
18 changes: 17 additions & 1 deletion src/server.rs
Original file line number Diff line number Diff line change
@@ -39,6 +39,7 @@ fn handle_request(
};

let file_path = output_folder.join(request_path);
let error_path = output_folder.join("404.html");

if file_path.is_file() {
match File::open(&file_path) {
@@ -70,6 +71,21 @@ fn handle_request(
request_path,
request.http_version()
);
Ok(Response::from_string("404 Not Found").with_status_code(404))
render_not_found(&error_path)
}
}

fn render_not_found(error_path: &PathBuf) -> Result<Response<Cursor<Vec<u8>>>, String> {
match File::open(&error_path) {
Ok(mut file) => {
let mut buffer = Vec::new();
std::io::copy(&mut file, &mut buffer).map_err(|e| e.to_string())?;
let resp = Response::from_data(buffer);
Ok(resp)
}
Err(err) => {
error!("Error on rendering page 404 - {}", err);
Ok(Response::from_string("404 Not Found").with_status_code(404))
}
}
}
50 changes: 48 additions & 2 deletions src/site.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,8 @@ use std::{fs, process, sync::Arc};
use tera::{Context, Tera};
use walkdir::WalkDir;

const NAME_BASED_SLUG_FILES: [&str; 1] = ["404.md"];

#[derive(Serialize)]
pub struct Data<'a> {
pub site: Marmite<'a>,
@@ -97,6 +99,29 @@ fn render_templates(site_data: &Data, tera: &Tera, output_dir: &Path) -> Result<
)?;
}

// Check and guarantees that page 404 was generated even if 404.md is removed
let file_404_path = output_dir.join("404.html");
if !file_404_path.exists() {
let mut content_context = global_context.clone();
let page_404_content = Content {
html: String::from("Page not found :/"),
title: String::from("Page not found"),
date: None,
slug: String::from(""),
extra: None,
tags: vec![],
};
content_context.insert("title", &page_404_content.title);
content_context.insert("content", &page_404_content);
render_html(
"content.html",
"404.html",
tera,
&content_context,
output_dir,
)?;
}

// Render tagged_contents
let mut unique_tags: Vec<(String, usize)> = Vec::new();
let tags_dir = output_dir.join("tag");
@@ -347,11 +372,32 @@ fn collect_content(content_dir: &std::path::PathBuf, site_data: &mut Data) {
.into_iter()
.filter_map(Result::ok)
.filter(|e| {
e.path().is_file() && e.path().extension().and_then(|ext| ext.to_str()) == Some("md")
let file_name = e
.path()
.file_name()
.and_then(|ext| ext.to_str())
.expect("Could not get file name");
let file_extension = e.path().extension().and_then(|ext| ext.to_str());
e.path().is_file()
&& !NAME_BASED_SLUG_FILES.contains(&file_name)
&& file_extension == Some("md")
})
.for_each(|entry| {
if let Err(e) = process_file(entry.path(), site_data) {
if let Err(e) = process_file(entry.path(), site_data, false) {
error!("Failed to process file {}: {}", entry.path().display(), e);
}
});

NAME_BASED_SLUG_FILES.into_iter().for_each(|slugged_file| {
let slugged_path = content_dir.join(slugged_file);
if slugged_path.exists() {
if let Err(e) = process_file(slugged_path.as_path(), site_data, true) {
error!(
"Failed to process file {}: {}",
slugged_path.as_path().display(),
e
);
}
}
})
}