repo.rs raw

use std::sync::Arc;

use anyhow::Error;
use poem::{
    IntoResponse, Request, Result, handler,
    web::{Data, Path},
};
use sailfish::TemplateOnce;

use crate::{
    App,
    render::{Links, Presentation, View},
    repos::Summary,
};

#[derive(TemplateOnce)]
#[template(path = "pages/repo.stpl.html")]
struct RepoPage {
    summary: Summary,
    clone_url: String,
    browse_url: String,
    readme: Option<Readme>,
}

struct Readme {
    file_name: String,
    url: String,
    raw_url: String,
    presentation: Presentation,
}

#[handler]
pub async fn handler(
    app: Data<&Arc<App>>,
    Path(repo): Path<String>,
    req: &Request,
) -> Result<impl IntoResponse> {
    let name = super::repo_name(&repo)?;
    let lookup_name = name.clone();
    let found = app
        .blocking(move |store| {
            let Some(repo) = store.open(&lookup_name)? else {
                return Ok(None);
            };
            let readme = repo
                .readme()?
                .map(|file| {
                    let links = Links::for_document(&lookup_name, &file.path);
                    Ok::<_, Error>(Readme {
                        file_name: file.path.file_name().unwrap_or_default().to_owned(),
                        url: links.url(View::File, &file.path),
                        raw_url: links.url(View::Raw, &file.path),
                        presentation: Presentation::of(&repo, &file, &links)?,
                    })
                })
                .transpose()?;
            Ok(Some((repo.summary(), readme)))
        })
        .await?;
    let (summary, readme) = super::found(found)?;
    let links = Links::for_document(&name, &Default::default());
    let title = summary.name.to_string();
    Ok(super::page(
        &app,
        title,
        RepoPage {
            clone_url: app.clone_url(req, &name),
            browse_url: links.url(View::File, &Default::default()),
            summary,
            readme,
        },
    )?)
}