1use std::sync::Arc;
2
3use askama::Template;
4use axum::{extract::Query, response::IntoResponse, Extension};
5use serde::Deserialize;
6
7use crate::{
8 git::{Commit, OpenRepository},
9 into_response,
10 methods::{
11 filters,
12 repo::{Repository, RepositoryPath, Result},
13 },
14 Git,
15};
16
17#[derive(Template)]
18#[template(path = "repo/commit.html")]
19pub struct View {
20 pub repo: Repository,
21 pub commit: Arc<Commit>,
22 pub branch: Option<Arc<str>>,
23 pub dl_branch: Arc<str>,
24 pub id: Option<String>,
25}
26
27#[derive(Deserialize)]
28pub struct UriQuery {
29 pub id: Option<String>,
30 #[serde(rename = "h")]
31 pub branch: Option<Arc<str>>,
32}
33
34pub async fn handle(
35 Extension(repo): Extension<Repository>,
36 Extension(RepositoryPath(repository_path)): Extension<RepositoryPath>,
37 Extension(git): Extension<Arc<Git>>,
38 Query(query): Query<UriQuery>,
39) -> Result<impl IntoResponse> {
40 let open_repo = git.repo(repository_path, query.branch.clone()).await?;
41
42 let (dl_branch, commit) = tokio::try_join!(
43 fetch_dl_branch(query.branch.clone(), open_repo.clone()),
44 fetch_commit(query.id.as_deref(), open_repo),
45 )?;
46
47 Ok(into_response(View {
48 repo,
49 commit,
50 branch: query.branch,
51 id: query.id,
52 dl_branch,
53 }))
54}
55
56async fn fetch_commit(
57 commit_id: Option<&str>,
58 open_repo: Arc<OpenRepository>,
59) -> Result<Arc<Commit>> {
60 Ok(if let Some(commit) = commit_id {
61 open_repo.commit(commit, true).await?
62 } else {
63 Arc::new(open_repo.latest_commit(true).await?)
64 })
65}
66
67async fn fetch_dl_branch(
68 branch: Option<Arc<str>>,
69 open_repo: Arc<OpenRepository>,
70) -> Result<Arc<str>> {
71 if let Some(branch) = branch.clone() {
72 Ok(branch)
73 } else {
74 Ok(Arc::from(
75 open_repo
76 .clone()
77 .default_branch()
78 .await?
79 .unwrap_or_else(|| "master".to_string()),
80 ))
81 }
82}