index.rs
raw
use std::sync::Arc;
use poem::{
IntoResponse, Result, handler,
web::{Data, Query},
};
use sailfish::TemplateOnce;
use serde::Deserialize;
use crate::{App, repos::Summary};
#[derive(Deserialize)]
pub struct PageQuery {
page: Option<usize>,
}
#[derive(TemplateOnce)]
#[template(path = "pages/index.stpl.html")]
struct IndexPage {
repos: Vec<Summary>,
page: usize,
pages: usize,
}
#[handler]
pub async fn handler(
app: Data<&Arc<App>>,
Query(query): Query<PageQuery>,
) -> Result<impl IntoResponse> {
let page = query.page.unwrap_or(1).max(1);
let page_size = app.config.page_size as usize;
let listing = app
.blocking(move |store| {
let names = store.public_names()?;
let pages = names.len().div_ceil(page_size).max(1);
if page > pages {
return Ok(None);
}
let mut repos = Vec::new();
for name in names.iter().skip((page - 1) * page_size).take(page_size) {
match store.open(name) {
Ok(Some(repo)) => repos.push(repo.summary()),
// Unpublished since the listing was taken.
Ok(None) => {}
// One broken repository must not take the whole site
// down; it is reported and left out.
Err(err) => tracing::warn!(
repo = %name,
error = format!("{err:#}"),
"leaving an unopenable repository out of the index"
),
}
}
Ok(Some(IndexPage { repos, page, pages }))
})
.await?;
let index = super::found(listing)?;
Ok(super::page(&app, "Repositories", index)?)
}