boomack-cli 0.3.0

CLI client for Boomack
use std::process::exit;

use clap::{Args, Subcommand};
use serde::Serialize;
use boomack::client::panels::{
    AllPanelExportParameters,
    PanelExportParameters,
    export_all_panels_request,
    export_panel_request,
};
use boomack::client::slots::{
    SlotExportParameters,
    export_slot_request,
};
use super::{CliConfig, parse_location, run_request};

#[derive(Args, Serialize)]
pub struct ExportCommandArguments {
    #[clap(subcommand)]
    command: ExportSubCommands,
}

#[derive(Subcommand, Serialize)]
pub enum ExportSubCommands {
    #[clap(about = "Export all panels to the filesystem on the server")]
    All(ExportAllPanelsArguments),

    #[clap(about = "Export one panel to the filesystem on the server")]
    Panel(ExportPanelArguments),

    #[clap(about = "Export one slot to the filesystem on the server")]
    Slot(ExportSlotArguments),
}


#[derive(Args, Serialize)]
pub struct ExportAllPanelsArguments {
    #[clap(short = 'p', long = "path", value_name = "SERVER_PATH",
        help = "A relative path in the filesystem of the server to export to")]
    path: Option<String>,

    #[clap(short = 't', long = "theme", value_name = "THEME",
        help = "A theme to use during the export")]
    theme: Option<String>,

    #[clap(short = 'z', long = "zoom", value_name = "ZOOM",
        help = "A CSS zoom level for the HTML")]
    zoom: Option<f32>,
}

impl<'l> ExportAllPanelsArguments {
    pub fn to_parameters(&'l self) -> AllPanelExportParameters<'l> {
        AllPanelExportParameters {
            path: self.path.as_deref(),
            theme: self.theme.as_deref(),
            zoom: self.zoom,
        }
    }
}

#[derive(Args, Serialize)]
pub struct ExportPanelArguments {
    #[clap(value_name = "PANEL_ID",
        help = "The ID of the panel; defaults to 'default'")]
    panel_id: Option<String>,

    #[clap(short = 'p', long = "path", value_name = "SERVER_PATH",
        help = "A relative path in the filesystem of the server to export to")]
    path: Option<String>,

    #[clap(short = 'n', long = "name", value_name = "NAME",
        help = "A name for the exported HTML file; without extension")]
    filename: Option<String>,

    #[clap(short = 't', long = "theme", value_name = "THEME",
        help = "A theme to use during the export")]
    theme: Option<String>,

    #[clap(short = 'z', long = "zoom", value_name = "ZOOM",
        help = "A CSS zoom level for the HTML")]
    zoom: Option<f32>,
}

impl<'l> ExportPanelArguments {
    pub fn to_parameters(&'l self) -> PanelExportParameters<'l> {
        PanelExportParameters {
            path: self.path.as_deref(),
            name: self.filename.as_deref(),
            theme: self.theme.as_deref(),
            zoom: self.zoom,
        }
    }
}

#[derive(Args, Serialize)]
pub struct ExportSlotArguments {
    #[clap(value_name = "TARGET",
        help = "The panel and slot ID, e. g. 'panel-1/main-slot'")]
    target: Option<String>,

    #[clap(short = 'p', long = "path", value_name = "SERVER_PATH",
        help = "A relative path in the filesystem of the server to export to")]
    path: Option<String>,

    #[clap(short = 'n', long = "name", value_name = "NAME",
        help = "A name for the exported HTML file; without extension")]
    filename: Option<String>,

    #[clap(short = 't', long = "theme", value_name = "THEME",
        help = "A theme to use during the export")]
    theme: Option<String>,

    #[clap(short = 'z', long = "zoom", value_name = "ZOOM",
        help = "A CSS zoom level for the HTML")]
    zoom: Option<f32>,
}

impl<'l> ExportSlotArguments {
    pub fn parse_target(&'l self) -> (Option<&'l str>, &'l str) {
        let (panel_id, slot_id) = parse_location(self.target.as_deref());
        if matches!(slot_id, None) {
            eprintln!("Target location is required");
            exit(1)
        }
        (panel_id, slot_id.unwrap())
    }
    pub fn to_parameters(&'l self) -> SlotExportParameters<'l> {
        SlotExportParameters {
            path: self.path.as_deref(),
            name: self.filename.as_deref(),
            theme: self.theme.as_deref(),
            zoom: self.zoom,
        }
    }
}

pub fn dispatch_export_command(cfg: &CliConfig, args: &ExportCommandArguments) -> i32 {
    let request = match &args.command {
        ExportSubCommands::All(args) => export_all_panels_request(args.to_parameters()),
        ExportSubCommands::Panel(args) => export_panel_request(args.panel_id.as_deref(), args.to_parameters()),
        ExportSubCommands::Slot(args) => {
            let (panel_id, slot_id) = args.parse_target();
            export_slot_request(panel_id, slot_id, args.to_parameters())
        },
    };

    run_request(cfg, request)
}