diff --git a/Cargo.lock b/Cargo.lock index 1d69ff1..3812cd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3999,6 +3999,7 @@ dependencies = [ "chrono-tz", "clap", "geo", + "indexmap", "itertools 0.13.0", "lettre", "log", diff --git a/vzdv-site/Cargo.toml b/vzdv-site/Cargo.toml index 407fa0f..40b87c8 100644 --- a/vzdv-site/Cargo.toml +++ b/vzdv-site/Cargo.toml @@ -14,6 +14,7 @@ publish = false [dependencies] vzdv = { path = "../vzdv" } +indexmap = "2.0" anyhow = "1.0.86" axum = { version = "0.7.4", features = ["multipart"] } axum-extra = "0.9.3" diff --git a/vzdv-site/src/endpoints/facility.rs b/vzdv-site/src/endpoints/facility.rs index b0e6ea8..a16610f 100644 --- a/vzdv-site/src/endpoints/facility.rs +++ b/vzdv-site/src/endpoints/facility.rs @@ -11,6 +11,7 @@ use axum::{ Form, Router, }; use chrono::{DateTime, Months, Utc}; +use indexmap::IndexMap; use itertools::Itertools; use log::{error, warn}; use minijinja::context; @@ -38,6 +39,8 @@ struct StaffPosition { description: &'static str, } +type ParsedAlias = Vec<(String, Vec<(String, Vec)>)>; + fn generate_staff_outline(config: &Config) -> HashMap<&'static str, StaffPosition> { let email_domain = &config.staff.email_domain; HashMap::from([ @@ -397,6 +400,71 @@ async fn page_resources( Ok(Html(rendered)) } +pub async fn fetch_and_parse_alias_file() -> Result { + let url = "https://data-api.vnas.vatsim.net/Files/Aliases/ZDV.txt"; + let response = reqwest::get(url).await?.text().await?; + + let mut parsed_data: IndexMap>> = IndexMap::new(); + let mut current_h1 = String::new(); + let mut current_h2 = String::new(); + + for line in response.lines() { + if line.starts_with(";;;;") { + // New Heading 1 + current_h1 = line.strip_prefix(";;;;").unwrap_or(line).trim().to_string(); + parsed_data.entry(current_h1.clone()).or_default(); + current_h2 = String::new(); // Reset H2 + } else if line.starts_with(";;;") { + // New Heading 2 + current_h2 = line.strip_prefix(";;;").unwrap_or(line).trim().to_string(); + parsed_data + .entry(current_h1.clone()) + .or_default() + .entry(current_h2.clone()) + .or_default(); + } else if line.starts_with('.') { + // Command under current H1 or H2 + if !current_h1.is_empty() { + if !current_h2.is_empty() { + parsed_data + .entry(current_h1.clone()) + .or_default() + .entry(current_h2.clone()) + .or_default() + .push(line.trim().to_string()); + } else { + // Command directly under H1 + parsed_data + .entry(current_h1.clone()) + .or_default() + .entry("__root__".to_string()) + .or_default() + .push(line.trim().to_string()); + } + } + } + } + + // Convert IndexMap to Vec for Jinja compatibility + let parsed_vec: ParsedAlias = parsed_data + .into_iter() + .map(|(h1, h2_map)| { + let h2_vec = h2_map.into_iter().collect(); + (h1, h2_vec) + }) + .collect(); + + Ok(parsed_vec) +} + +/// View Alias commands for the facility. (Polled from the vNAS API) +async fn alias_ref(State(state): State>) -> Result, AppError> { + let template = state.templates.get_template("facility/aliasref.jinja")?; + let alias_ref = fetch_and_parse_alias_file().await?; + let rendered = template.render(context! { alias_ref })?; + Ok(Html(rendered)) +} + /// Check visitor requirements and submit an application. async fn page_visitor_application( State(state): State>, @@ -583,6 +651,7 @@ pub fn router() -> Router> { .route("/facility/staff", get(page_staff)) .route("/facility/activity", get(page_activity)) .route("/facility/resources", get(page_resources)) + .route("/facility/aliasref", get(alias_ref)) .route( "/facility/visitor_application", get(page_visitor_application), diff --git a/vzdv-site/templates/_layout.jinja b/vzdv-site/templates/_layout.jinja index 720e5d6..6d88d2d 100644 --- a/vzdv-site/templates/_layout.jinja +++ b/vzdv-site/templates/_layout.jinja @@ -81,6 +81,7 @@
  • Roster
  • Activity
  • Resources
  • +
  • Alias Reference
  • Visitor Application
  • diff --git a/vzdv-site/templates/facility/aliasref.jinja b/vzdv-site/templates/facility/aliasref.jinja new file mode 100644 index 0000000..4c28ff3 --- /dev/null +++ b/vzdv-site/templates/facility/aliasref.jinja @@ -0,0 +1,99 @@ +{% extends "_layout.jinja" %} + +{% block title %}Alias Reference | {{ super() }}{% endblock %} + +{% block body %} + +

    Alias Reference

    + + +
    + {% for h1, h2_list in alias_ref %} + + + {{ h1 }} + +
    + {% set parent_index = loop.index %} + {% for h2, commands in h2_list %} + {% if h2 == "__root__" %} + + {% for command in commands %} +
    + {{ command }} +
    + {% endfor %} + {% else %} + + + {{ h2 }} + +
    + {% for command in commands %} + +
    + {{ command }} +
    + {% endfor %} +
    + {% endif %} + {% endfor %} +
    + {% endfor %} +
    + + + +{% endblock %}