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 }