nina 1.0.0

API for the Bundesamt für Bevölkerungsschutz
Documentation
use curl::easy::Easy;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

fn curl(url: &str) -> String {
    let mut dst = Vec::new();
    let mut easy = Easy::new();
    easy.url(url).unwrap();

    {
        let mut transfer = easy.transfer();
        transfer
            .write_function(|data| {
                dst.extend_from_slice(data);
                Ok(data.len())
            })
            .unwrap();
        transfer.perform().unwrap();
    }

    String::from_utf8_lossy(&dst).to_string()
}

/// Returns the Overview of a AGS-specific region
///
/// # Examples
///
/// ```
/// use nina::overview;
///
/// let warnings = overview("091620000000").unwrap();
/// ```
pub fn overview(ags: &str) -> Result<Vec<AGSOverviewResult>, serde_json::Error> {
    let url = format!("https://warnung.bund.de/api31/dashboard/{}.json", ags);
    let json = curl(&url);
    let overview: Vec<AGSOverviewResult> = serde_json::from_str(&json)?;

    Ok(overview)
}

/// Returns the Warnings given by the mowas warn system
///
/// # Examples
///
/// ```
/// use nina::mowas;
///
/// let warnings = mowas().unwrap();
/// ```
pub fn mowas() -> Result<Vec<MapWarning>, serde_json::Error> {
    let json = curl("https://warnung.bund.de/api31/mowas/mapData.json");
    let map_warnings: Vec<MapWarning> = serde_json::from_str(&json)?;

    Ok(map_warnings)
}

/// Returns the Warnings given for the katwarn app
///
/// # Examples
///
/// ```
/// use nina::katwarn;
///
/// let warnings = katwarn().unwrap();
/// ```
pub fn katwarn() -> Result<Vec<MapWarning>, serde_json::Error> {
    let json = curl("https://warnung.bund.de/api31/katwarn/mapData.json");
    let map_warnings: Vec<MapWarning> = serde_json::from_str(&json)?;

    Ok(map_warnings)
}

/// Returns the Warnings given for the biwapp
///
/// # Examples
///
/// ```
/// use nina::biwapp;
///
/// let warnings = biwapp().unwrap();
/// ```
pub fn biwapp() -> Result<Vec<MapWarning>, serde_json::Error> {
    let json = curl("https://warnung.bund.de/api31/biwapp/mapData.json");
    let map_warnings: Vec<MapWarning> = serde_json::from_str(&json)?;

    Ok(map_warnings)
}

/// Returns the Coronavirus rules by AGS.
///
/// # Arguments
///
/// * `ags` - AGSs (Amtlicher Gebietsschlüssel) for the region of the covid rules.
///
/// # Examples
///
/// ```
/// use nina::covidrules;
///
/// let covidrules = covidrules("091620000000").unwrap();
/// println!("{}", covidrules.general_info);
/// ```
///
/// If you need a AGS, look at: <https://www.xrepository.de/api/xrepository/urn:de:bund:destatis:bevoelkerungsstatistik:schluessel:rs_2021-07-31/download/Regionalschl_ssel_2021-07-31.json>
pub fn covidrules(ags: &str) -> Result<AGSCovidRules, serde_json::Error> {
    let url = format!(
        "https://warnung.bund.de/api31/appdata/covid/covidrules/DE/{}.json",
        ags
    );
    let json = curl(&url);
    let covidrules: AGSCovidRules = serde_json::from_str(&json)?;

    Ok(covidrules)
}

/// Severity of a warning
#[derive(Serialize, Deserialize, Debug)]
pub enum Severity {
    Minor,
    Severe,
}

/// Type of a warning
#[derive(Serialize, Deserialize, Debug)]
pub enum Type {
    Alert,
    Update,
    Cancel,
}

/// Type of a warning (for AGSOverviewResult)
// TODO: Waiting for <https://github.com/serde-rs/serde/pull/1902>
#[derive(Serialize, Deserialize, Debug)]
pub enum OverviewType {
    ALERT,
    UPDATE,
    CANCEL,
}

/// Warning about a topic in a region
#[derive(Serialize, Deserialize, Debug)]
pub struct MapWarning {
    pub id: String,
    pub version: i32,
    #[serde(rename = "startDate")]
    pub start_date: String,
    pub severity: Severity,
    pub r#type: Type,
    #[serde(rename = "i18nTitle")]
    pub i18n_title: HashMap<String, String>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Level {
    pub headline: String,
    pub range: String,
    #[serde(rename = "backgroundColor")]
    pub background_color: String,
    #[serde(rename = "textColor")]
    pub text_color: String,
}

/// Source of the covid rules
#[derive(Serialize, Deserialize, Debug)]
pub enum Source {
    LAND,
    BUND,
    KREIS,
}

/// Specifc rules for the covidvirus
#[derive(Serialize, Deserialize, Debug)]
pub struct Rules {
    pub id: String,
    pub caption: String,
    pub text: String,
    pub source: Source,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Common {
    pub id: String,
    pub caption: String,
    pub text: String,
}

#[derive(Serialize, Deserialize, Debug)]
/// CovidRules Root format by AGS
pub struct AGSCovidRules {
    pub key: String,
    pub level: Level,
    #[serde(rename = "generalInfo")]
    pub general_info: String,
    pub rules: Vec<Rules>,
    // TODO: Regulations
    pub common: Vec<Common>,
}

#[derive(Serialize, Deserialize, Debug)]
/// Provider of the AGSOverviewResult
pub enum Provider {
    MOWAS,
}

#[derive(Serialize, Deserialize, Debug)]
/// Data of the AGSOverviewResult
pub struct Data {
    headline: String,
    provider: Provider,
    severity: Severity,
    // TODO: transKeys
    // TODO: area
}

#[derive(Serialize, Deserialize, Debug)]
/// Payload of the AGSOverviewResult
pub struct Payload {
    pub version: i32,
    pub r#type: OverviewType,
    pub id: String,
    pub hash: String,
    pub data: Data,
}

#[derive(Serialize, Deserialize, Debug)]
/// Result of a Overview request with AGS
pub struct AGSOverviewResult {
    pub id: String,
    pub payload: Payload,
    #[serde(rename = "i18nTitle")]
    pub i18n_title: HashMap<String, String>,
    pub sent: String,
}

#[cfg(test)]
mod tests {
    use crate::*;

    #[test]
    fn test_overview() {
        let overview = overview("091620000000").unwrap();
        println!("{:#?}", overview);
    }

    #[test]
    fn test_mowas() {
        let mowas = mowas().unwrap();
        println!("{:#?}", mowas);
    }

    #[test]
    fn test_katwarn() {
        let katwarn = katwarn().unwrap();
        println!("{:#?}", katwarn);
    }

    #[test]
    fn test_biwapp() {
        let biwapp = biwapp().unwrap();
        println!("{:#?}", biwapp);
    }

    #[test]
    fn test_covidrules() {
        let covidrules = covidrules("091620000000").unwrap();
        println!("{:#?}", covidrules);
    }
}

#[cfg(doctest)]
mod test_readme {
    macro_rules! external_doc_test {
        ($x:expr) => {
            #[doc = $x]
            extern "C" {}
        };
    }

    external_doc_test!(include_str!("../README.md"));
}