taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

setup.rs (6401B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2025, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::fmt::Write as _;
     18 
     19 use taler_common::config::Config;
     20 use tracing::{debug, error, info, warn};
     21 
     22 use crate::{
     23     config::SetupCfg,
     24     cyclos_api::{api::CyclosAuth, client::Client},
     25 };
     26 
     27 pub async fn setup(cfg: &Config, _reset: bool, client: &http_client::Client) -> anyhow::Result<()> {
     28     let cfg = SetupCfg::parse(cfg)?;
     29     let client = Client {
     30         client,
     31         api_url: &cfg.host.api_url,
     32         auth: &CyclosAuth::Basic {
     33             username: cfg.host.username,
     34             password: cfg.host.password,
     35         },
     36     };
     37 
     38     info!(target: "setup", "Check API access and configuration");
     39     let mut ready = true;
     40 
     41     let data = Client {
     42         auth: &CyclosAuth::None,
     43         ..client
     44     }
     45     .data_for_ui()
     46     .await?;
     47 
     48     info!(target: "setup", "Connecting to '{}' v{}-{}", data.application_name, data.cyclos_version, &data.cyclos_revision[..8]);
     49 
     50     // Check root URL
     51     if cfg.root != data.root_url {
     52         warn!(target: "setup",
     53             "Expected CYCLOS_URL '{}' from config got '{}' from server",
     54             cfg.root, data.root_url
     55         );
     56     }
     57 
     58     let whoami = client.whoami().await?;
     59     if let Some(id) = cfg.id {
     60         if whoami.id != id {
     61             error!(
     62                 target: "setup",
     63                 "Expected ACCOUNT_ID {id} from config got {} from server",
     64                 whoami.id
     65             );
     66             ready = false;
     67         } else {
     68             debug!(target: "setup", "ACCOUNT_ID {id} from config match server")
     69         }
     70     } else {
     71         error!(target: "setup", "Missing ACCOUNT_ID got {} from server", whoami.id);
     72         ready = false;
     73     }
     74     if let Some(name) = cfg.name {
     75         if whoami.name != name {
     76             warn!(
     77                 target: "setup",
     78                 "Expected NAME '{name}' from config got '{}' from server",
     79                 whoami.name
     80             )
     81         } else {
     82             debug!(target: "setup", "NAME {name} from config match server")
     83         }
     84     } else {
     85         error!(target: "setup", "Missing NAME got '{}' from server", whoami.name);
     86         ready = false;
     87     }
     88 
     89     // Check account type
     90     let accounts = client.accounts().await?;
     91     let currency = if accounts.is_empty() {
     92         debug!(target: "setup", "No accounts found, there is some issues in the Cyclos configuration");
     93         ready = false;
     94         None
     95     } else {
     96         let accounts_fmt = {
     97             let mut s = String::new();
     98             for a in &accounts {
     99                 write!(
    100                     &mut s,
    101                     "\n{} '{}' in {}",
    102                     a.ty.id, a.ty.name, a.currency.ty.name,
    103                 )
    104                 .unwrap();
    105             }
    106             s
    107         };
    108         if let Some(id) = cfg.account_type_id {
    109             if let Some(p) = accounts.iter().find(|it| it.ty.id == id) {
    110                 debug!(target: "setup", "ACCOUNT_TYPE_ID {id} in config is one of:{accounts_fmt}");
    111                 Some(&p.currency)
    112             } else {
    113                 error!(target: "setup", "Unknown ACCOUNT_TYPE_ID {id} in config, must be one of:{accounts_fmt}");
    114                 ready = false;
    115                 None
    116             }
    117         } else {
    118             error!(target: "setup", "Missing ACCOUNT_TYPE_ID in config, must be one of:{accounts_fmt}");
    119             ready = false;
    120             None
    121         }
    122     };
    123 
    124     if let Some(currency) = currency {
    125         // Check currency
    126         if currency.ty.name != cfg.currency.as_ref() {
    127             warn!(target: "setup",
    128                 "Expected CURRENCY '{}' from config got '{}' from server",
    129                 cfg.currency, currency.ty.name
    130             );
    131         }
    132     }
    133 
    134     // Check payment type
    135     let data = client.payment_data().await?;
    136     if data.payment_types.is_empty() {
    137         debug!(target: "setup", "No payment ids found, there is some issues in the Cyclos configuration");
    138         ready = false;
    139     } else {
    140         let payment_fmt = {
    141             let mut s = String::new();
    142             for p in &data.payment_types {
    143                 if let Some(currency) = currency {
    144                     if p.currency.ty.id == currency.ty.id {
    145                         write!(&mut s, "\n{} '{}'", p.ty.id, p.ty.name).unwrap();
    146                     }
    147                 } else {
    148                     write!(
    149                         &mut s,
    150                         "\n{} '{}' in {}",
    151                         p.ty.id, p.ty.name, p.currency.ty.name
    152                     )
    153                     .unwrap();
    154                 }
    155             }
    156             s
    157         };
    158         if let Some(id) = cfg.payment_type_id {
    159             if let Some(p) = data.payment_types.iter().find(|it| it.ty.id == id) {
    160                 if let Some(currency) = currency
    161                     && p.currency.ty.id != currency.ty.id
    162                 {
    163                     error!(target: "setup", "PAYMENT_TYPE_ID {} in config use currency {} expected {}, must be one of:{payment_fmt}", p.ty.id, p.currency.ty.name, currency.ty.name);
    164                     ready = false
    165                 } else {
    166                     debug!(target: "setup", "PAYMENT_TYPE_ID {id} config is one of:{payment_fmt}");
    167                 }
    168             } else {
    169                 error!(target: "setup", "Unknown PAYMENT_TYPE_ID {id} in config, must be one of:{payment_fmt}");
    170                 ready = false;
    171             }
    172         } else {
    173             error!(target: "setup", "Missing PAYMENT_TYPE_ID in config, must be one of:{payment_fmt}");
    174             ready = false;
    175         }
    176     }
    177 
    178     if ready {
    179         info!(target: "setup", "Setup finished");
    180         Ok(())
    181     } else {
    182         error!(target: "setup", "Setup failed, config need editing");
    183         std::process::exit(0);
    184     }
    185 }