// Back - An extremely simple git issue tracking system. Inspired by tvix's // panettone // // Copyright (C) 2024 Benedikt Peetz // SPDX-License-Identifier: AGPL-3.0-or-later // // This file is part of Back. // // You should have received a copy of the License along with this program. // If not, see . use std::path::Path; use crate::{ issues::issue::{Issue, Status}, SOURCE_CODE_REPOSITORY, }; use format::BackString; use gix::{refs::Target, Repository}; use issue_show::BackPrefix; use rocket::{ get, response::content::{RawCss, RawHtml}, }; use crate::REPOSITORY; mod format; mod issue; mod issue_show; #[get("/style.css")] pub fn styles() -> RawCss { RawCss(include_str!("../../assets/style.css").to_owned()) } fn list_all_issues(repo: &'_ Repository) -> Vec> { repo.refs .iter() .expect("We should be able to iterate over references") .prefixed(Path::new("refs/bugs/")) .expect("The 'refs/bugs/' namespace should exist") .map(|val| { let reference = val.expect("'val' should be an object?"); if let Target::Object(commit_id) = reference.target { Issue::from_commit_id(repo, commit_id) } else { unreachable!("All 'refs/bugs/' should contain a clear target."); } }) .collect() } pub fn issue_list_boilerplate(wanted_status: Status, counter_status: Status) -> RawHtml { let repository = REPOSITORY.get().expect("This should have been set"); let issue_list = list_all_issues(&repository.to_thread_local()) .iter() .fold(String::new(), |acc, val| { format!("{}{}", acc, &issue_to_string(val, wanted_status).0) }); let counter_status_lower = counter_status.to_string().to_lowercase(); RawHtml(format!( r#" Back

{wanted_status} Issues

    {issue_list}
"#, SOURCE_CODE_REPOSITORY.get().expect("This should be set") )) } #[get("/issues/open")] pub fn open() -> RawHtml { issue_list_boilerplate(Status::Open, Status::Closed) } #[get("/issues/closed")] pub fn closed() -> RawHtml { issue_list_boilerplate(Status::Closed, Status::Open) } #[get("/issue/")] pub fn show_issue(prefix: BackPrefix) -> RawHtml { let repository = REPOSITORY .get() .expect("This should have been set") .to_thread_local(); let all_issues = list_all_issues(&repository); let maybe_issue = all_issues .iter() .find(|issue| issue.id.to_string().starts_with(&prefix.to_string())); match maybe_issue { Some(issue) => issue.to_html(), None => RawHtml(format!("Issue with id '{prefix}' not found!")), } } fn issue_to_string(issue: &Issue<'_>, status: Status) -> RawHtml { if issue.status == status { issue.to_list_entry() } else { RawHtml(String::default()) } }