229 lines
8.2 KiB
Rust
229 lines
8.2 KiB
Rust
use std::path::PathBuf;
|
|
|
|
extern crate historian;
|
|
use historian::{Historian, Page, Edit, PageRenderer, export_wiki, Linker};
|
|
|
|
#[macro_use] extern crate rocket;
|
|
use rocket::serde::json::Json;
|
|
use rocket::Responder;
|
|
use rocket::response::{Redirect, content::{RawHtml, RawText}};
|
|
use rocket::form::Form;
|
|
use rocket::http::uri::Origin;
|
|
use rocket::fs::NamedFile;
|
|
use rocket::State;
|
|
|
|
extern crate clap;
|
|
use clap::Parser;
|
|
|
|
extern crate grep;
|
|
|
|
#[macro_use] extern crate toml;
|
|
|
|
#[derive(Responder)]
|
|
enum PageResponder {
|
|
Redirect(Redirect),
|
|
File(NamedFile),
|
|
Page(RawHtml<String>),
|
|
Text(RawText<String>)
|
|
}
|
|
|
|
#[get("/<path..>")]
|
|
async fn page<'r>(
|
|
path: PathBuf, origin: &Origin<'r>,
|
|
historian: &State<Historian>, renderer: &State<PageRenderer>
|
|
) -> Option<PageResponder> {
|
|
let path_str = path.to_str().unwrap();
|
|
if let Some(resource_path) = renderer.resolve_to_resource(path_str) {
|
|
Some(PageResponder::File(NamedFile::open(resource_path).await.unwrap()))
|
|
} else if let Some(attachment_path) = historian.resolve_to_attachment(path_str) {
|
|
Some(PageResponder::File(NamedFile::open(attachment_path).await.unwrap()))
|
|
} else {
|
|
historian.resolve_to_page(path_str).map(|page| {
|
|
if let Some(query) = origin.query() {
|
|
for (key, value) in query.segments() {
|
|
if key == "action" {
|
|
if value == "edit" {
|
|
return PageResponder::Page(RawHtml(renderer.render_page_template("edit.html", &historian, &page, &toml! {
|
|
dynamic = true
|
|
})))
|
|
} else if value == "history" {
|
|
return PageResponder::Page(RawHtml(renderer.template("history.html")
|
|
.with_historian(&historian)
|
|
.with_page(&page)
|
|
.insert("revisions", &historian.get_history_of_page(&page))
|
|
.insert("options", &toml! {
|
|
dynamic = true
|
|
})
|
|
.render()))
|
|
}
|
|
}
|
|
|
|
if key == "revision" {
|
|
if let Some(revision) = historian.get_revision_by_id(value) {
|
|
return PageResponder::Page(RawHtml(renderer.template("revision.html")
|
|
.with_historian(&historian)
|
|
.with_page(&page)
|
|
.insert("revision", &revision)
|
|
.insert("content", &historian.get_page_text_of_revision(&page, &revision).unwrap())
|
|
.insert("options", &toml! {
|
|
dynamic = true
|
|
})
|
|
.render()))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if page.is_directory && !origin.path().ends_with("/") {
|
|
PageResponder::Redirect(Redirect::to(origin.path().as_str().to_owned() + "/"))
|
|
} else {
|
|
PageResponder::Page(RawHtml(renderer.render_page(&historian, &page, &toml! {
|
|
dynamic = true
|
|
})))
|
|
}
|
|
}).or_else(|| {
|
|
if let Some(query) = origin.query() {
|
|
for (key, value) in query.segments() {
|
|
if key == "action" && value == "edit" {
|
|
return Some(PageResponder::Page(RawHtml(renderer.template("edit.html")
|
|
.with_historian(&historian)
|
|
.with_url(&path_str)
|
|
.insert("page", &historian.start_page(path_str))
|
|
.insert("content", "")
|
|
.insert("ancestors", &Vec::<String>::with_capacity(0))
|
|
.insert("options", &toml! {
|
|
dynamic = true
|
|
})
|
|
.render())))
|
|
}
|
|
}
|
|
None
|
|
} else {
|
|
Some(PageResponder::Redirect(Redirect::to(origin.path().as_str().to_owned() + "?action=edit")))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(FromForm)]
|
|
struct PageAction<'r> {
|
|
content: &'r str,
|
|
author: &'r str,
|
|
summary: &'r str,
|
|
subaction: &'r str
|
|
}
|
|
|
|
#[post("/<path..>", data = "<action>")]
|
|
fn action(
|
|
path: PathBuf, origin: &Origin,
|
|
historian: &State<Historian>, renderer: &State<PageRenderer>,
|
|
action: Form<PageAction<'_>>
|
|
) -> PageResponder {
|
|
let path_str = path.to_str().unwrap();
|
|
let page = historian.resolve_to_page(path_str).unwrap_or_else(|| historian.start_page(path_str));
|
|
|
|
if let Some(query) = origin.query() {
|
|
println!("{:?}", query);
|
|
for (key, value) in query.segments() {
|
|
if key == "action" {
|
|
if value == "edit" {
|
|
if action.subaction == "preview" {
|
|
return PageResponder::Page(RawHtml(renderer.template("edit.html")
|
|
.with_page(&page)
|
|
.with_historian(&historian)
|
|
.insert("content", action.content)
|
|
.insert("subaction", action.subaction)
|
|
.insert("summary", action.summary)
|
|
.insert("author", action.author)
|
|
.insert("options", &toml! {
|
|
dynamic = true
|
|
})
|
|
.render()))
|
|
} else {
|
|
historian.submit_edit(&page, &Edit {
|
|
author: Some(action.author.to_owned()),
|
|
summary: action.summary.to_owned(),
|
|
content: action.content.to_owned()
|
|
});
|
|
return PageResponder::Redirect(Redirect::to(origin.path().as_str().to_owned()))
|
|
}
|
|
} else if value == "resolvelinks" {
|
|
let linker = Linker::new(&historian);
|
|
return PageResponder::Text(RawText(linker.resolve_links_for_edit(&page, &Edit {
|
|
author: None,
|
|
summary: action.summary.to_owned(),
|
|
content: action.content.to_owned()
|
|
})))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PageResponder::Page(RawHtml(renderer.render_template("message.html", &historian, &toml! {
|
|
header = "Invalid Action"
|
|
message = "Action was invalid or misunderstood"
|
|
}, &toml! {
|
|
dynamic = true
|
|
})))
|
|
}
|
|
|
|
#[derive(Parser)]
|
|
#[command(version, about, long_about = None)]
|
|
struct Args {
|
|
/// Path to wiki repository
|
|
wiki_path: String,
|
|
|
|
/// Render the wiki to a static website
|
|
#[arg(long)]
|
|
render_to: Option<String>,
|
|
|
|
/// Resolve a link to a page on the wiki
|
|
#[arg(long)]
|
|
resolve_link: Option<String>,
|
|
|
|
/// Resolve all wiki links in the given page, output the modified text
|
|
#[arg(long)]
|
|
resolve_links: Option<String>,
|
|
|
|
/// Path to templates
|
|
#[arg(long)]
|
|
template_path: Option<String>
|
|
}
|
|
|
|
#[rocket::main]
|
|
async fn main() {
|
|
let args = Args::parse();
|
|
let historian = Historian::new(args.wiki_path);
|
|
|
|
let renderer = if let Some(template_path) = args.template_path {
|
|
PageRenderer::with_template_path(&template_path)
|
|
} else {
|
|
PageRenderer::new()
|
|
};
|
|
|
|
let linker = Linker::new(&historian);
|
|
|
|
if let Some(resolve_link) = args.resolve_link {
|
|
println!("{}", linker.resolve_link(&resolve_link).unwrap());
|
|
return;
|
|
}
|
|
|
|
if let Some(resolve_links) = args.resolve_links {
|
|
let page = historian.resolve_to_page(&resolve_links).expect("failed to find page");
|
|
println!("{}", linker.resolve_links(&page));
|
|
return;
|
|
}
|
|
|
|
if let Some(render_to) = args.render_to {
|
|
export_wiki(&historian, &renderer, &render_to);
|
|
return;
|
|
}
|
|
|
|
rocket::build()
|
|
.manage(historian)
|
|
.manage(renderer)
|
|
.mount("/", routes![page, action])
|
|
.launch()
|
|
.await;
|
|
}
|