1use anyhow::Context;
2use askama::Template;
3use axum::{extract::Query, response::Response, Extension};
4use serde::Deserialize;
5use yoke::Yoke;
6
7use crate::{
8 database::schema::{commit::YokedCommit, repository::YokedRepository},
9 into_response,
10 methods::{
11 filters,
12 repo::{Repository, Result, DEFAULT_BRANCHES},
13 },
14};
15
16#[derive(Deserialize)]
17pub struct UriQuery {
18 #[serde(rename = "ofs")]
19 offset: Option<usize>,
20 #[serde(rename = "h")]
21 branch: Option<String>,
22}
23
24#[derive(Template)]
25#[template(path = "repo/log.html")]
26pub struct View<'a> {
27 repo: Repository,
28 commits: Vec<&'a crate::database::schema::commit::Commit<'a>>,
29 next_offset: Option<usize>,
30 branch: Option<String>,
31}
32
33pub async fn handle(
34 Extension(repo): Extension<Repository>,
35 Extension(db): Extension<sled::Db>,
36 Query(query): Query<UriQuery>,
37) -> Result<Response> {
38 let offset = query.offset.unwrap_or(0);
39
40 let repository = crate::database::schema::repository::Repository::open(&db, &*repo)?
41 .context("Repository does not exist")?;
42 let mut commits =
43 get_branch_commits(&repository, &db, query.branch.as_deref(), 101, offset).await?;
44
45 let next_offset = if commits.len() == 101 {
46 commits.pop();
47 Some(offset + 100)
48 } else {
49 None
50 };
51
52 let commits = commits.iter().map(Yoke::get).collect();
53
54 Ok(into_response(&View {
55 repo,
56 commits,
57 next_offset,
58 branch: query.branch,
59 }))
60}
61
62pub async fn get_branch_commits(
63 repository: &YokedRepository,
64 database: &sled::Db,
65 branch: Option<&str>,
66 amount: usize,
67 offset: usize,
68) -> Result<Vec<YokedCommit>> {
69 let reference = branch.map(|branch| format!("refs/heads/{branch}"));
70
71 if let Some(reference) = reference {
72 let commit_tree = repository.get().commit_tree(database, &reference)?;
73 return Ok(commit_tree.fetch_latest(amount, offset).await);
74 }
75
76 for branch in DEFAULT_BRANCHES {
77 let commit_tree = repository.get().commit_tree(database, branch)?;
78 let commits = commit_tree.fetch_latest(amount, offset).await;
79
80 if !commits.is_empty() {
81 return Ok(commits);
82 }
83 }
84
85 Ok(vec![])
86}