diff options
Diffstat (limited to 'pkgs/by-name/ba/back/src/web/mod.rs')
-rw-r--r-- | pkgs/by-name/ba/back/src/web/mod.rs | 148 |
1 files changed, 72 insertions, 76 deletions
diff --git a/pkgs/by-name/ba/back/src/web/mod.rs b/pkgs/by-name/ba/back/src/web/mod.rs index ed91e7e..1e6a5af 100644 --- a/pkgs/by-name/ba/back/src/web/mod.rs +++ b/pkgs/by-name/ba/back/src/web/mod.rs @@ -9,125 +9,121 @@ // You should have received a copy of the License along with this program. // If not, see <https://www.gnu.org/licenses/agpl.txt>. -use std::path::Path; - use crate::{ config::BackConfig, - web::issue::{Issue, Status}, + error::{self, Error}, + git_bug::{ + dag::issues_from_repository, + issue::{CollapsedIssue, Status}, + }, }; -use gix::{refs::Target, Repository}; -use issue_show::BackPrefix; +use prefix::BackPrefix; use rocket::{ get, response::content::{RawCss, RawHtml}, State, }; -mod format; -mod issue; -mod issue_show; +mod issue_html; +pub mod prefix; #[get("/style.css")] pub fn styles() -> RawCss<String> { RawCss(include_str!("../../assets/style.css").to_owned()) } -fn list_all_issues(repo: &'_ Repository) -> Vec<Issue<'_>> { - 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( config: &State<BackConfig>, wanted_status: Status, counter_status: Status, -) -> RawHtml<String> { +) -> error::Result<RawHtml<String>> { let repository = &config.repository; - let issue_list = list_all_issues(&repository.to_thread_local()) - .iter() + let issue_list = issues_from_repository(&repository.to_thread_local())? + .into_iter() .fold(String::new(), |acc, val| { - format!("{}{}", acc, &issue_to_string(val, wanted_status).0) + 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(); - RawHtml(format!( + Ok(RawHtml(format!( r#" -<!DOCTYPE html> -<html lang="en"> - <head> - <title>Back</title> - <link href="/style.css" rel="stylesheet" type="text/css"> - <meta content="width=device-width,initial-scale=1" name="viewport"> - </head> - <body> - <div class="content"> - <header> - <h1>{wanted_status} Issues</h1> - </header> - <main> - <div class="issue-links"> - <a href="/issues/{counter_status_lower}/">View {counter_status} issues</a> - <a href="{}">Source code</a> - <!-- - <form class="issue-search" method="get"> - <input name="search" title="Issue search query" type="search"> - <input class="sr-only" type="submit" value="Search Issues"> - </form> - --> - </div> - <ol class="issue-list"> - {issue_list} - </ol> - </main> - </div> - </body> -</html> -"#, + <!DOCTYPE html> + <html lang="en"> + <head> + <title>Back</title> + <link href="/style.css" rel="stylesheet" type="text/css"> + <meta content="width=device-width,initial-scale=1" name="viewport"> + </head> + <body> + <div class="content"> + <header> + <h1>{wanted_status} Issues</h1> + </header> + <main> + <div class="issue-links"> + <a href="/issues/{counter_status_lower}/">View {counter_status} issues</a> + <a href="{}">Source code</a> + <!-- + <form class="issue-search" method="get"> + <input name="search" title="Issue search query" type="search"> + <input class="sr-only" type="submit" value="Search Issues"> + </form> + --> + </div> + <ol class="issue-list"> + {issue_list} + </ol> + </main> + </div> + </body> + </html> + "#, config.source_code_repository_url - )) + ))) } #[get("/issues/open")] -pub fn open(config: &State<BackConfig>) -> RawHtml<String> { +pub fn open(config: &State<BackConfig>) -> error::Result<RawHtml<String>> { issue_list_boilerplate(config, Status::Open, Status::Closed) } #[get("/issues/closed")] -pub fn closed(config: &State<BackConfig>) -> RawHtml<String> { +pub fn closed(config: &State<BackConfig>) -> error::Result<RawHtml<String>> { issue_list_boilerplate(config, Status::Closed, Status::Open) } #[get("/issue/<prefix>")] -pub fn show_issue(config: &State<BackConfig>, prefix: BackPrefix) -> RawHtml<String> { +pub fn show_issue( + config: &State<BackConfig>, + prefix: Result<BackPrefix, gix::hash::prefix::from_hex::Error>, +) -> error::Result<RawHtml<String>> { + // 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 = list_all_issues(&repository); + let all_issues: Vec<CollapsedIssue> = 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) => issue.to_html(config), - None => RawHtml(format!("Issue with id '{prefix}' not found!")), - } -} - -fn issue_to_string(issue: &Issue<'_>, status: Status) -> RawHtml<String> { - if issue.status == status { - issue.to_list_entry() - } else { - RawHtml(String::default()) + Some(issue) => Ok(issue.to_html(config)), + None => Err(Error::IssuesPrefixMissing { prefix }), } } |