// 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 crate::{ config::BackConfig, error::{self, Error}, git_bug::{ dag::issues_from_repository, issue::{CollapsedIssue, Status}, }, }; use prefix::BackPrefix; use rocket::{ get, response::content::{RawCss, RawHtml}, State, }; mod issue_html; pub mod prefix; #[get("/style.css")] pub fn styles() -> RawCss { RawCss(include_str!("../../assets/style.css").to_owned()) } pub fn issue_list_boilerplate( config: &State, wanted_status: Status, counter_status: Status, ) -> error::Result> { let repository = &config.repository; let issue_list = issues_from_repository(&repository.to_thread_local())? .into_iter() .fold(String::new(), |acc, val| { let issue = val.collaps(); format!("{}{}", acc, { if issue.status == wanted_status { let issue_entry = issue.to_list_entry(); issue_entry.0 } else { String::new() } }) }); let counter_status_lower = counter_status.to_string().to_lowercase(); Ok(RawHtml(format!( r#" Back

{wanted_status} Issues

    {issue_list}
"#, config.source_code_repository_url ))) } #[get("/issues/open")] pub fn open(config: &State) -> error::Result> { issue_list_boilerplate(config, Status::Open, Status::Closed) } #[get("/issues/closed")] pub fn closed(config: &State) -> error::Result> { issue_list_boilerplate(config, Status::Closed, Status::Open) } #[get("/issue/")] pub fn show_issue( config: &State, prefix: Result, ) -> error::Result> { // NOTE(@bpeetz): Explicitly unwrap the `prefix` here (instead of taking the unwrapped value as // argument), to avoid triggering rockets "errors forward to the next route" feature. // This ensures, that our error message actually reaches the user. <2024-12-26> let prefix = prefix?; let repository = config.repository.to_thread_local(); let all_issues: Vec = issues_from_repository(&repository)? .into_iter() .map(|val| val.collapse()) .collect(); let maybe_issue = all_issues .iter() .find(|issue| issue.id.to_string().starts_with(&prefix.to_string())); match maybe_issue { Some(issue) => Ok(issue.to_html(config)), None => Err(Error::IssuesPrefixMissing { prefix }), } }