about summary refs log tree commit diff stats
path: root/src/web/responses.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-06 15:45:11 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-06-06 15:45:11 +0200
commita6baea06697f6c76c695dc4198099deb8ba916e0 (patch)
tree476a3865f6b4bef04751ba20534813a58892811b /src/web/responses.rs
parentchore: Initial commit (diff)
downloadback-a6baea06697f6c76c695dc4198099deb8ba916e0.zip
feat(treewide): Prepare for first release
This commit contains many changes, as they were developed alongside
`git-bug-rs` and unfortunately not separately committed.

A toplevel summary would include:
- Appropriate redirects,
- The templating moved to `vy` (as this works with rustfmt formatting),
- Search support (via `git-bug-rs`),
- And better layout in the link section.
Diffstat (limited to 'src/web/responses.rs')
-rw-r--r--src/web/responses.rs135
1 files changed, 125 insertions, 10 deletions
diff --git a/src/web/responses.rs b/src/web/responses.rs
index bcdcc0a..00af35a 100644
--- a/src/web/responses.rs
+++ b/src/web/responses.rs
@@ -12,10 +12,13 @@
 use std::convert::Infallible;
 
 use bytes::Bytes;
+use git_bug::replica::entity::id::prefix::IdPrefix;
 use http::{Response, StatusCode, Version};
 use http_body_util::{BodyExt, Full, combinators::BoxBody};
+use vy::{IntoHtml, h1, p, pre};
 
-use crate::{error, git_bug::format::HtmlString};
+use super::generate::templates::make_page;
+use crate::error;
 
 pub(super) fn html_response<T: Into<Bytes>>(html_text: T) -> Response<BoxBody<Bytes, Infallible>> {
     html_response_status(html_text, StatusCode::OK)
@@ -28,6 +31,15 @@ pub(super) fn html_response_status<T: Into<Bytes>>(
     html_response_status_content_type(html_text, status, "text/html")
 }
 
+pub(super) fn redirect(target: &str) -> Response<BoxBody<Bytes, Infallible>> {
+    Response::builder()
+        .status(StatusCode::MOVED_PERMANENTLY)
+        .version(Version::HTTP_2)
+        .header("Location", target)
+        .body(full(""))
+        .expect("This is hardcoded and will build")
+}
+
 pub(super) fn html_response_status_content_type<T: Into<Bytes>>(
     html_text: T,
     status: StatusCode,
@@ -36,26 +48,129 @@ pub(super) fn html_response_status_content_type<T: Into<Bytes>>(
     Response::builder()
         .status(status)
         .version(Version::HTTP_2)
-        .header("Content-Type", format!("{}; charset=utf-8", content_type))
+        .header("Content-Type", format!("{content_type}; charset=utf-8"))
         .header("x-content-type-options", "nosniff")
         .header("x-frame-options", "SAMEORIGIN")
         .body(full(html_text))
         .expect("This will always build")
 }
 
-fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, Infallible> {
+pub(super) fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, Infallible> {
     Full::new(chunk.into()).boxed()
 }
 
-// FIXME: Not all errors should return `INTERNAL_SERVER_ERROR`. <2025-03-08>
 impl error::Error {
+    #[allow(clippy::too_many_lines)]
     pub fn into_response(self) -> Response<BoxBody<Bytes, Infallible>> {
-        html_response_status(
-            format!(
-                "<h1> Internal server error. </h1> <pre>Error: {}</pre>",
-                HtmlString::from(self.to_string())
+        match self {
+            error::Error::ConfigParse { .. }
+            | error::Error::ProjectListRead { .. }
+            | error::Error::ConfigRead { .. }
+            | error::Error::RepoGetReferences(_)
+            | error::Error::RepoIssueRead(_)
+            | error::Error::RepoIdentityRead(_)
+            | error::Error::RepoFind { .. }
+            | error::Error::RepoRefsIter(_)
+            | error::Error::RepoRefsPrefixed { .. }
+            | error::Error::TcpBind { .. }
+            | error::Error::RepoOpen { .. }
+            | error::Error::TcpAccept { .. } => html_response_status(
+                make_page(
+                    (
+                        h1!("Internal server error"),
+                        pre!(format!("Error {}", self.to_string())),
+                    ),
+                    "Error page",
+                    Some("Error | Back"),
+                )
+                .into_string(),
+                StatusCode::INTERNAL_SERVER_ERROR,
+            ),
+            error::Error::NotGitBug { path } => html_response_status(
+                make_page(
+                    (
+                        h1!("Expectation Failed"),
+                        p!(
+                            "Repository '",
+                            path.display().to_string(),
+                            "' has no git bug data to show."
+                        ),
+                    ),
+                    "Error page",
+                    Some("Error | Back"),
+                )
+                .into_string(),
+                StatusCode::EXPECTATION_FAILED,
+            ),
+            error::Error::IssuesPrefixMissing { prefix, err } => html_response_status(
+                make_page(
+                    (
+                        h1!("Expectation Failed"),
+                        p!(
+                            "There is no issue associated with the prefix ",
+                            "'",
+                            prefix.to_string(),
+                            "': ",
+                            err.to_string()
+                        ),
+                    ),
+                    "Error page",
+                    Some("Error | Back"),
+                )
+                .into_string(),
+                StatusCode::EXPECTATION_FAILED,
+            ),
+            error::Error::IssuesPrefixParse { prefix, error } => html_response_status(
+                make_page(
+                    (
+                        h1!("Expectation Failed"),
+                        p!(
+                            "The prefix '",
+                            prefix,
+                            "' cannot be interperted as a prefix",
+                        ),
+                        p!(error.to_string()),
+                        p!(
+                            "The prefix is composed of  ",
+                            IdPrefix::REQUIRED_LENGTH,
+                            " or more hex chars."
+                        ),
+                    ),
+                    "Error page",
+                    Some("Error | Back"),
+                )
+                .into_string(),
+                StatusCode::EXPECTATION_FAILED,
+            ),
+            error::Error::NotFound(path_buf) => html_response_status(
+                make_page(
+                    (
+                        h1!("Expectation Failed"),
+                        p!(
+                            "The path '",
+                            path_buf.display().to_string(),
+                            "' was unkonwn",
+                        ),
+                    ),
+                    "Error page",
+                    Some("Error | Back"),
+                )
+                .into_string(),
+                StatusCode::EXPECTATION_FAILED,
+            ),
+            error::Error::InvalidQuery { err, query } => html_response_status(
+                make_page(
+                    (
+                        h1!("Expectation Failed"),
+                        p!("The query '", query, "' was invalid",),
+                        p!(err.to_string()),
+                    ),
+                    "Error page",
+                    Some("Error | Back"),
+                )
+                .into_string(),
+                StatusCode::EXPECTATION_FAILED,
             ),
-            StatusCode::INTERNAL_SERVER_ERROR,
-        )
+        }
     }
 }