raw
1use axum::{
2 extract::State,
3 http::StatusCode,
4 response::{IntoResponse, Response},
5};
6
7use crate::{
8 BileState,
9 config::Config,
10 error::{Context as _, Result},
11 git::Repository,
12 http::{
13 extractor::{RepoName, Tag},
14 path::Path,
15 response::{ErrorPage, Html, Redirect},
16 },
17 utils::filters,
18};
19
20#[derive(askama::Template)]
21#[template(path = "tag.html")]
22struct Template<'a> {
23 config: &'a Config,
24 repo: &'a Repository,
25 tag: git2::Tag<'a>,
26}
27
28#[tracing::instrument(skip_all)]
29pub(crate) async fn get(
30 state: State<BileState>,
31 Path((repo_name, tag)): Path<(RepoName, Tag)>,
32) -> Response {
33 state
34 .spawn(move |state| inner(&state, &repo_name, &tag))
35 .await
36}
37
38#[tracing::instrument(skip_all)]
39fn inner(state: &BileState, repo_name: &RepoName, tag: &Tag) -> Result<Response> {
40 let Some(repo) = Repository::open(&state.config, repo_name).context("opening repository")?
41 else {
42 return Ok(ErrorPage::from(state)
43 .with_status(StatusCode::NOT_FOUND)
44 .into_response());
45 };
46
47 let Ok(repo_tag) = repo.tag(tag) else {
48 return Ok(Redirect::permanent(&format!("/{repo_name}/commit/{tag}"))
49 .unwrap_or(Redirect::PERMANENT_ROOT)
50 .into_response());
51 };
52
53 Ok(Html(Template {
54 config: &state.config,
55 repo: &repo,
56 tag: repo_tag,
57 })
58 .into_response())
59}
60