aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs/by-name/ba/back/src/web/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--pkgs/by-name/ba/back/src/web/mod.rs148
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 }),
}
}