git-gemini-forge 0.6.4

A simple Gemini server that serves a read-only view of public repositories from a Git forge.
use super::templates::PercentEncoded;
use crate::config::*;
use crate::network;
use crate::network::net::Net;
use windmark::response::Response;

/// Answers with Gemtext that consists of an overview of a repository.
pub fn handler(
	cfg: &Config,
	net: &Net,
	username: PercentEncoded,
	repo_name: PercentEncoded,
) -> Result<Response, network::error::Error> {
	let repo = &cfg.forge_api().get_repo(net, &username, &repo_name)?;
	let kind = cfg.forge_kind.to_string();
	let repo_http_url = &repo.html_url;
	let repo_http = format!("\n\n=> {repo_http_url} View on {kind}");

	// Describe parent
	let fork = match &repo.parent {
		None => String::new(),
		Some(parent) => format!(
			"=> /{}/{} Forked from {}/{}\n",
			parent.owner.login, parent.name, parent.owner.login, parent.name
		),
	};

	// List branches
	let branches = &cfg.forge_api().get_branches(net, &username, &repo_name)?;

	// Transform repos into Gemtext internal page links
	let branches_list: Vec<String> = branches
		.iter()
		.map(|branch| super::templates::branch_link(repo, branch))
		.collect();

	// Format branches into a Gemtext list
	let gemtext_branches_list: String = branches_list
		.iter()
		.map(|b: &String| format!("{b}\n"))
		.collect::<Vec<String>>()
		.concat();

	// List file tree
	let contents = &cfg.forge_api().get_file_tree(net, &username, &repo_name)?;

	// Transform contents into Gemtext internal page links
	let contents_list: Vec<String> = contents
		.iter()
		.map(|file| super::templates::file_link(repo, None, file))
		.collect();

	// Format top-level tree into a Gemtext list
	let gemtext_tree_list: String = contents_list
		.iter()
		.map(|f| format!("{f}\n"))
		.collect::<Vec<String>>()
		.concat();

	// TODO: Render README.gmi if exists

	let description = if repo.description.is_empty() {
		String::new()
	} else {
		format!("\n{}", repo.description)
	};

	let website = if repo.website.is_empty() {
		String::new()
	} else {
		format!("\n=> {}", repo.website)
	};

	let gemtext: String = format!(
		"## {}/{}{description}{website}
{fork}
=> /{} Back to {}
### Branches
{gemtext_branches_list}
### Tree
{gemtext_tree_list}{repo_http}",
		username.display(),
		repo_name.display(),
		username.uri_component(),
		username.display()
	);

	Ok(Response::success(gemtext))
}