multiberry-backend/src/api/consents.rs

93 lines
3.3 KiB
Rust

// src/api/consents.rs
// Consent request and retrieval logic - Functional style
use super::{client::{BankClient, BankingError}, models::{ConsentRequestBody, ConsentResponse}};
use tracing::{info, debug, error};
impl BankClient {
pub async fn request_consent(&self, client_id: &str) -> Result<ConsentResponse, BankingError> {
info!("🔐 Requesting consent for client_id: {}", client_id);
let body = self.build_consent_request(client_id);
let token = self.get_token().await?;
debug!("✅ Got bank token");
debug!("📤 Sending consent request to bank");
let response = self.http_client
.post(self.base_url.join("/account-consents/request")?)
.bearer_auth(token)
.header("x-requesting-bank", self.client_id.as_str())
.json(&body)
.send()
.await?;
debug!("📥 Bank response status: {}", response.status());
response
.text()
.await
.map_err(Into::into)
.and_then(|text| self.parse_consent_response(&text))
}
fn build_consent_request(&self, client_id: &str) -> ConsentRequestBody {
ConsentRequestBody {
client_id: client_id.to_string(),
permissions: vec![
"ReadAccountsDetail".to_string(),
"ReadBalances".to_string(),
"ReadTransactionsDetail".to_string(),
],
reason: "Account aggregation for Multiberry app".to_string(),
requesting_bank: self.client_id.clone(),
requesting_bank_name: "Multiberry Backend".to_string(),
}
}
fn parse_consent_response(&self, text: &str) -> Result<ConsentResponse, BankingError> {
info!("✅ Bank consent response: {}", text);
serde_json::from_str::<ConsentResponse>(text)
.map_err(|e| {
error!("❌ Failed to deserialize ConsentResponse: {}", e);
error!("Raw response was: {}", text);
BankingError::ApiError {
status: 500,
body: format!("Deserialization error: {}", e),
}
})
.map(|consent| {
info!("✅ Successfully parsed consent: {}", consent.consent_id);
consent
})
}
pub async fn delete_consent(&self, consent_id: &str) -> Result<(), BankingError> {
info!("🗑️ Deleting consent: {}", consent_id);
let token = self.get_token().await?;
let response = self.http_client
.delete(self.base_url.join(&format!("/account-consents/{}", consent_id))?)
.bearer_auth(token)
.header("x-fapi-interaction-id", format!("team275-{}", chrono::Utc::now().timestamp()))
.send()
.await?;
match response.status().as_u16() {
204 => {
info!("✅ Consent deleted successfully");
Ok(())
},
status => {
error!("❌ Failed to delete consent: {}", status);
Err(BankingError::ApiError {
status,
body: response.text().await.unwrap_or_default(),
})
}
}
}
}