client.rs (4204B)
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::borrow::Cow; 18 19 use http_client::sse::SseClient; 20 use hyper::Method; 21 use jiff::Timestamp; 22 use serde_json::json; 23 use taler_common::types::amount::Decimal; 24 use url::Url; 25 26 use crate::cyclos_api::{ 27 api::{ApiResult, CyclosAuth, CyclosRequest}, 28 types::{ 29 Account, DataForTransaction, DataForUi, HistoryItem, OrderBy, Pagination, Transaction, 30 Transfer, User, 31 }, 32 }; 33 34 pub struct Client<'a> { 35 pub client: &'a http_client::Client, 36 pub api_url: &'a Url, 37 pub auth: &'a CyclosAuth, 38 } 39 40 impl Client<'_> { 41 fn request(&self, method: Method, path: impl Into<Cow<'static, str>>) -> CyclosRequest<'_> { 42 CyclosRequest::new(self.client, method, self.api_url, path, self.auth) 43 } 44 45 pub async fn data_for_ui(&self) -> ApiResult<DataForUi> { 46 self.request(Method::GET, "ui/data-for-ui") 47 .parse_json() 48 .await 49 } 50 51 pub async fn whoami(&self) -> ApiResult<User> { 52 self.request(Method::GET, "users/self").parse_json().await 53 } 54 55 pub async fn accounts(&self) -> ApiResult<Vec<Account>> { 56 self.request(Method::GET, "self/accounts") 57 .parse_json() 58 .await 59 } 60 61 pub async fn balance(&self, account_type_id: i64) -> ApiResult<Account> { 62 self.request(Method::GET, format!("self/accounts/{account_type_id}")) 63 .parse_json() 64 .await 65 } 66 67 pub async fn payment_data(&self) -> ApiResult<DataForTransaction> { 68 self.request(Method::GET, "self/payments/data-for-perform") 69 .parse_json() 70 .await 71 } 72 73 pub async fn direct_payment( 74 &self, 75 creditor: i64, 76 payment_type_id: i64, 77 amount: Decimal, 78 description: &str, 79 ) -> ApiResult<Transaction> { 80 self.request(Method::POST, "self/payments") 81 .json(&json!({ 82 "description": description, 83 "scheduling": "direct", 84 "subject": creditor, 85 "type": payment_type_id, 86 "amount": amount 87 })) 88 .parse_json() 89 .await 90 } 91 92 pub async fn chargeback(&self, transfer_id: i64) -> ApiResult<i64> { 93 self.request(Method::POST, format!("transfers/{transfer_id}/chargeback")) 94 .parse_json() 95 .await 96 } 97 98 pub async fn history( 99 &self, 100 account_type_id: i64, 101 order_by: OrderBy, 102 page: u64, 103 since: Option<Timestamp>, 104 ) -> ApiResult<Pagination<Vec<HistoryItem>>> { 105 let mut req = self 106 .request( 107 Method::GET, 108 format!("self/accounts/{account_type_id}/history"), 109 ) 110 .query("orderBy", order_by) 111 .query("skipTotalCount", false) 112 .query("page", page); 113 if let Some(since) = since { 114 req = req.query("datePeriod", since) 115 } 116 req.query("begin", since).parse_pagination().await 117 } 118 119 pub async fn transfer(&self, transfer_id: i64) -> ApiResult<Transfer> { 120 self.request(Method::GET, format!("transfers/{transfer_id}")) 121 .parse_json() 122 .await 123 } 124 125 pub async fn push_notifications( 126 &self, 127 client_id: i64, 128 sse_client: &mut SseClient, 129 ) -> ApiResult<()> { 130 self.request(Method::GET, "push/subscribe") 131 .query("clientId", client_id) 132 .query("kinds", "newNotification") 133 .into_sse(sse_client) 134 .await 135 } 136 }