about summary refs log tree commit diff stats
path: root/pkgs/by-name/ba/back/src/web
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/by-name/ba/back/src/web')
-rw-r--r--pkgs/by-name/ba/back/src/web/generate/mod.rs225
-rw-r--r--pkgs/by-name/ba/back/src/web/mod.rs127
-rw-r--r--pkgs/by-name/ba/back/src/web/responses.rs50
3 files changed, 0 insertions, 402 deletions
diff --git a/pkgs/by-name/ba/back/src/web/generate/mod.rs b/pkgs/by-name/ba/back/src/web/generate/mod.rs
deleted file mode 100644
index ae783a3..0000000
--- a/pkgs/by-name/ba/back/src/web/generate/mod.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-use std::{fs, path::Path};
-
-use gix::hash::Prefix;
-use log::info;
-use rinja::Template;
-use url::Url;
-
-use crate::{
-    config::BackConfig,
-    error,
-    git_bug::{
-        dag::issues_from_repository,
-        issue::{CollapsedIssue, Status},
-    },
-};
-
-#[derive(Template)]
-#[template(path = "./issues.html")]
-struct IssuesTemplate {
-    wanted_status: Status,
-    counter_status: Status,
-    issues: Vec<CollapsedIssue>,
-
-    /// The path to the repository
-    repo_path: String,
-
-    /// The URL to `back`'s source code
-    source_code_repository_url: Url,
-}
-pub fn issues(
-    config: &BackConfig,
-    wanted_status: Status,
-    counter_status: Status,
-    repo_path: &Path,
-) -> error::Result<String> {
-    let repository = config
-        .repositories()?
-        .get(repo_path)?
-        .open(&config.scan_path)?;
-
-    let mut issue_list = issues_from_repository(&repository.to_thread_local())?
-        .into_iter()
-        .map(|issue| issue.collapse())
-        .filter(|issue| issue.status == wanted_status)
-        .collect::<Vec<CollapsedIssue>>();
-
-    // Sort by date descending.
-    // SAFETY:
-    // The time stamp is only used for sorting, so a malicious attacker could only affect the issue
-    // sorting.
-    issue_list.sort_by_key(|issue| unsafe { issue.timestamp.to_unsafe() });
-    issue_list.reverse();
-
-    Ok(IssuesTemplate {
-        wanted_status,
-        counter_status,
-        source_code_repository_url: config.source_code_repository_url.clone(),
-        issues: issue_list,
-        repo_path: repo_path.display().to_string(),
-    }
-    .render()
-    .expect("This should always work"))
-}
-
-use crate::git_bug::format::HtmlString;
-#[derive(Template)]
-#[template(path = "./issue.html")]
-struct IssueTemplate {
-    issue: CollapsedIssue,
-
-    /// The path to the repository
-    repo_path: String,
-
-    /// The URL to `back`'s source code
-    source_code_repository_url: Url,
-}
-pub fn issue(config: &BackConfig, repo_path: &Path, prefix: Prefix) -> error::Result<String> {
-    let repository = config
-        .repositories()?
-        .get(repo_path)?
-        .open(&config.scan_path)?
-        .to_thread_local();
-
-    let maybe_issue = issues_from_repository(&repository)?
-        .into_iter()
-        .map(|val| val.collapse())
-        .find(|issue| issue.id.to_string().starts_with(&prefix.to_string()));
-
-    match maybe_issue {
-        Some(issue) => Ok(IssueTemplate {
-            issue,
-            repo_path: repo_path.display().to_string(),
-            source_code_repository_url: config.source_code_repository_url.clone(),
-        }
-        .render()
-        .expect("This should always work")),
-        None => Err(error::Error::IssuesPrefixMissing { prefix }),
-    }
-}
-
-#[derive(Template)]
-#[template(path = "./repos.html")]
-struct ReposTemplate {
-    repos: Vec<RepoValue>,
-
-    /// The URL to `back`'s source code
-    source_code_repository_url: Url,
-}
-struct RepoValue {
-    description: String,
-    owner: String,
-    path: String,
-}
-pub fn repos(config: &BackConfig) -> error::Result<String> {
-    let repos: Vec<RepoValue> = config
-        .repositories()?
-        .iter()
-        .filter_map(|raw_repo| match raw_repo.open(&config.scan_path) {
-            Ok(repo) => {
-                let repo = repo.to_thread_local();
-                let git_config = repo.config_snapshot();
-
-                let path = raw_repo.path().to_string_lossy().to_string();
-
-                let owner = git_config
-                    .string("cgit.owner")
-                    .map(|v| v.to_string())
-                    .unwrap_or("<No owner>".to_owned());
-
-                let description = fs::read_to_string(repo.git_dir().join("description"))
-                    .unwrap_or("<No description>".to_owned());
-
-                Some(RepoValue {
-                    description,
-                    owner,
-                    path,
-                })
-            }
-            Err(err) => {
-                info!(
-                    "Repo '{}' could not be opened: '{err}'",
-                    raw_repo.path().display()
-                );
-                None
-            }
-        })
-        .collect();
-
-    Ok(ReposTemplate {
-        repos,
-        source_code_repository_url: config.source_code_repository_url.clone(),
-    }
-    .render()
-    .expect("this should work"))
-}
-
-pub fn feed(config: &BackConfig, repo_path: &Path) -> error::Result<String> {
-    use rss::{ChannelBuilder, Item, ItemBuilder};
-
-    let repository = config
-        .repositories()?
-        .get(repo_path)?
-        .open(&config.scan_path)?
-        .to_thread_local();
-
-    let issues: Vec<CollapsedIssue> = issues_from_repository(&repository)?
-        .into_iter()
-        .map(|issue| issue.collapse())
-        .collect();
-
-    // Collect all Items as rss items
-    let mut items: Vec<Item> = issues
-        .iter()
-        .map(|issue| {
-            ItemBuilder::default()
-                .title(issue.title.to_string())
-                .author(issue.author.to_string())
-                .description(issue.message.to_string())
-                .pub_date(issue.timestamp.to_string())
-                .link(format!(
-                    "/{}/{}/issue/{}",
-                    repo_path.display(),
-                    &config.root_url,
-                    issue.id
-                ))
-                .build()
-        })
-        .collect();
-
-    // Append all comments after converting them to rss items
-    items.extend(
-        issues
-            .iter()
-            .filter(|issue| !issue.comments.is_empty())
-            .flat_map(|issue| {
-                issue
-                    .comments
-                    .iter()
-                    .map(|comment| {
-                        ItemBuilder::default()
-                            .title(issue.title.to_string())
-                            .author(comment.author.to_string())
-                            .description(comment.message.to_string())
-                            .pub_date(comment.timestamp.to_string())
-                            .link(format!(
-                                "/{}/{}/issue/{}",
-                                repo_path.display(),
-                                &config.root_url,
-                                issue.id
-                            ))
-                            .build()
-                    })
-                    .collect::<Vec<Item>>()
-            })
-            .collect::<Vec<Item>>(),
-    );
-
-    let channel = ChannelBuilder::default()
-        .title("Issues")
-        .link(config.root_url.to_string())
-        .description(format!("The rss feed for issues on {}.", &config.root_url))
-        .items(items)
-        .build();
-    Ok(channel.to_string())
-}
diff --git a/pkgs/by-name/ba/back/src/web/mod.rs b/pkgs/by-name/ba/back/src/web/mod.rs
deleted file mode 100644
index cc087ab..0000000
--- a/pkgs/by-name/ba/back/src/web/mod.rs
+++ /dev/null
@@ -1,127 +0,0 @@
-use bytes::Bytes;
-use http_body_util::combinators::BoxBody;
-use hyper::{server::conn::http1, service::service_fn, Method, Request, Response, StatusCode};
-use hyper_util::rt::TokioIo;
-use log::{error, info};
-use responses::{html_response, html_response_status, html_response_status_content_type};
-use tokio::net::TcpListener;
-
-use std::{convert::Infallible, net::SocketAddr, path::PathBuf, sync::Arc};
-
-use crate::{config::BackConfig, error, git_bug::issue::Status};
-
-mod generate;
-mod responses;
-
-async fn match_uri(
-    config: Arc<BackConfig>,
-    req: Request<hyper::body::Incoming>,
-) -> Result<Response<BoxBody<Bytes, Infallible>>, hyper::Error> {
-    if req.method() != Method::GET {
-        return Ok(html_response_status(
-            "Only get requests are supported",
-            StatusCode::NOT_ACCEPTABLE,
-        ));
-    }
-
-    let output = || -> Result<Response<BoxBody<Bytes, Infallible>>, error::Error> {
-        match req.uri().path().trim_end_matches("/") {
-            "" => Ok(html_response(generate::repos(&config)?)),
-
-            "/style.css" => Ok(responses::html_response_status_content_type(
-                include_str!("../../assets/style.css"),
-                StatusCode::OK,
-                "text/css",
-            )),
-
-            path if path.ends_with("/issues/open") => {
-                let repo_path = PathBuf::from(
-                    path.strip_suffix("/issues/open")
-                        .expect("This suffix exists")
-                        .strip_prefix("/")
-                        .expect("This also exists"),
-                );
-
-                let issues = generate::issues(&config, Status::Open, Status::Closed, &repo_path)?;
-                Ok(html_response(issues))
-            }
-            path if path.ends_with("/issues/closed") => {
-                let repo_path = PathBuf::from(
-                    path.strip_suffix("/issues/closed")
-                        .expect("This suffix exists")
-                        .strip_prefix("/")
-                        .expect("This also exists"),
-                );
-
-                let issues = generate::issues(&config, Status::Closed, Status::Open, &repo_path)?;
-                Ok(html_response(issues))
-            }
-            path if path.ends_with("/issues/feed") => {
-                let repo_path = PathBuf::from(
-                    path.strip_suffix("/issues/feed")
-                        .expect("This suffix exists")
-                        .strip_prefix("/")
-                        .expect("This also exists"),
-                );
-
-                let feed = generate::feed(&config, &repo_path)?;
-                Ok(html_response_status_content_type(
-                    feed,
-                    StatusCode::OK,
-                    "text/xml",
-                ))
-            }
-
-            path if path.contains("/issue/") => {
-                let (repo_path, prefix) = {
-                    let split: Vec<&str> = path.split("/issue/").collect();
-
-                    let prefix =
-                        gix::hash::Prefix::from_hex(split[1]).map_err(error::Error::from)?;
-
-                    let repo_path =
-                        PathBuf::from(split[0].strip_prefix("/").expect("This prefix exists"));
-
-                    (repo_path, prefix)
-                };
-                Ok(html_response(generate::issue(&config, &repo_path, prefix)?))
-            }
-
-            other => Ok(responses::html_response_status_content_type(
-                format!("'{}' not found", other),
-                StatusCode::NOT_FOUND,
-                "text/plain",
-            )),
-        }
-    };
-    match output() {
-        Ok(response) => Ok(response),
-        Err(err) => Ok(err.into_response()),
-    }
-}
-
-pub async fn main(config: Arc<BackConfig>) -> Result<(), error::Error> {
-    let addr: SocketAddr = ([127, 0, 0, 1], 8000).into();
-
-    let listener = TcpListener::bind(addr)
-        .await
-        .map_err(|err| error::Error::TcpBind { addr, err })?;
-    info!("Listening on http://{}", addr);
-    loop {
-        let (stream, _) = listener
-            .accept()
-            .await
-            .map_err(|err| error::Error::TcpAccept { err })?;
-        let io = TokioIo::new(stream);
-
-        let local_config = Arc::clone(&config);
-
-        let service = service_fn(move |req| match_uri(Arc::clone(&local_config), req));
-
-        tokio::task::spawn(async move {
-            if let Err(err) = http1::Builder::new().serve_connection(io, service).await {
-                error!("Error serving connection: {:?}", err);
-            }
-        });
-    }
-}
diff --git a/pkgs/by-name/ba/back/src/web/responses.rs b/pkgs/by-name/ba/back/src/web/responses.rs
deleted file mode 100644
index e50f8c2..0000000
--- a/pkgs/by-name/ba/back/src/web/responses.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use std::convert::Infallible;
-
-use bytes::Bytes;
-use http::{Response, StatusCode, Version};
-use http_body_util::{combinators::BoxBody, BodyExt, Full};
-
-use crate::{error, git_bug::format::HtmlString};
-
-pub(super) fn html_response<T: Into<Bytes>>(html_text: T) -> Response<BoxBody<Bytes, Infallible>> {
-    html_response_status(html_text, StatusCode::OK)
-}
-
-pub(super) fn html_response_status<T: Into<Bytes>>(
-    html_text: T,
-    status: StatusCode,
-) -> Response<BoxBody<Bytes, Infallible>> {
-    html_response_status_content_type(html_text, status, "text/html")
-}
-
-pub(super) fn html_response_status_content_type<T: Into<Bytes>>(
-    html_text: T,
-    status: StatusCode,
-    content_type: &str,
-) -> Response<BoxBody<Bytes, Infallible>> {
-    Response::builder()
-        .status(status)
-        .version(Version::HTTP_2)
-        .header("Content-Type", format!("{}; charset=utf-8", content_type))
-        .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> {
-    Full::new(chunk.into()).boxed()
-}
-
-// FIXME: Not all errors should return `INTERNAL_SERVER_ERROR`. <2025-03-08>
-impl error::Error {
-    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())
-            ),
-            StatusCode::INTERNAL_SERVER_ERROR,
-        )
-    }
-}