johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
//! Markdown as the pages will show it once posted:
//! `dev.knotless.renderMarkdown`, which a composer's preview asks. It is
//! the same renderer the pages' comments, bodies and READMEs are drawn
//! with, raw HTML shown as text but for `<details>` folds, and links
//! kept to the web's and the repository's own, so what is previewed is
//! what is shown. It reads nothing and fetches nothing: no login is
//! needed, and the text it takes is no longer than a body may be.
use super::repo::invalid;
use super::*;
/// The longest text it renders, in bytes: as long as a comment's, an
/// issue's or a pull's body may be.
const LONGEST: usize = 20_000;
/// The most a request may carry: the text at its longest, each byte of it
/// escaped in JSON as six, and the repository beside it.
const BODY_LIMIT: usize = 8 * LONGEST;
/// The preview the composers ask for.
pub fn routes() -> Router<Arc<App>> {
Router::new().route(
"/xrpc/dev.knotless.renderMarkdown",
post(render_markdown).layer(axum::extract::DefaultBodyLimit::max(BODY_LIMIT)),
)
}
#[derive(Deserialize)]
pub struct RenderInput {
text: String,
repo: Option<String>,
}
/// `dev.knotless.renderMarkdown`'s answer.
#[derive(Serialize)]
pub struct Rendered {
html: String,
}
/// `dev.knotless.renderMarkdown`.
pub async fn render_markdown(axum::Json(input): axum::Json<RenderInput>) -> Result<Response> {
if input.text.len() > LONGEST {
let why = format!("text is longer than {LONGEST} bytes");
return Err(invalid(why));
}
let base = match input.repo.as_deref() {
Some(uri) => root(uri)?,
None => String::new(),
};
let html = written(&input.text, &base, None, &HashMap::new());
Ok(answer(Rendered { html }))
}
/// Where the pages show the repository whose record `uri` names, as its
/// thread's page names it: what relative links in what is said there
/// resolve under. Only the name is read; the repository is not looked up.
fn root(uri: &str) -> Result<String> {
match knotless::aturi::AtUri::parse(uri) {
Ok(at) if at.collection == nsid::REPO => {
let (authority, name) = (url_path(&at.author), url_path(repo_name(&at.rkey)));
Ok(format!("/{authority}/{name}"))
}
_ => Err(invalid(format!(
"{uri} is not at://<authority>/{}/<name>",
nsid::REPO
))),
}
}