Compare commits
6 Commits
4d347a657c
...
improvemen
Author | SHA1 | Date | |
---|---|---|---|
c0a444e833 | |||
5a9da2d29a | |||
3de7ca94a2 | |||
6255dc1c2f | |||
c3fb162732 | |||
3ea95e9ec9 |
20
.gitea/workflows/test.yaml
Normal file
20
.gitea/workflows/test.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
name: Gitea Actions Demo
|
||||||
|
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Explore-Gitea-Actions:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
|
||||||
|
- run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by Gitea!"
|
||||||
|
- run: echo "🔎 The name of your branch is ${{ gitea.ref }} and your repository is ${{ gitea.repository }}."
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- run: echo "💡 The ${{ gitea.repository }} repository has been cloned to the runner."
|
||||||
|
- run: echo "🖥️ The workflow is now ready to test your code on the runner."
|
||||||
|
- name: List files in the repository
|
||||||
|
run: |
|
||||||
|
ls ${{ gitea.workspace }}
|
||||||
|
- run: echo "🍏 This job's status is ${{ job.status }}. And this is the last piece of the action."
|
||||||
|
|
@@ -6,8 +6,7 @@ keywords = ["bunq", "api"]
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/yuri91/bunq-rs"
|
repository = "https://github.com/yuri91/bunq-rs"
|
||||||
authors = ["Yuri Iozzelli <y.iozzelli@gmail.com>"]
|
authors = ["Yuri Iozzelli <y.iozzelli@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.79"
|
anyhow = "1.0.79"
|
||||||
|
35
examples/download_statement.rs
Normal file
35
examples/download_statement.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use bunq::{BunqConfig, CsvType, StatementFormat};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
let cfg = BunqConfig::load()?;
|
||||||
|
|
||||||
|
let client = cfg.install()?;
|
||||||
|
|
||||||
|
let accs = client.monetary_accounts()?;
|
||||||
|
|
||||||
|
let acc = &accs[0];
|
||||||
|
|
||||||
|
let stmt_id = client.request_statement(
|
||||||
|
acc,
|
||||||
|
StatementFormat::CSV(CsvType::Semicolon),
|
||||||
|
"2023-12-05",
|
||||||
|
"2023-12-15",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
println!("Waiting for statement {:?}...", stmt_id);
|
||||||
|
|
||||||
|
let mut ready = client.is_statement_ready(acc, stmt_id)?;
|
||||||
|
while !ready {
|
||||||
|
println!("Statement is not ready yet. Waiting 5 seconds...");
|
||||||
|
std::thread::sleep(Duration::from_secs(5));
|
||||||
|
ready = client.is_statement_ready(acc, stmt_id)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let contents = client.download_statement(acc, stmt_id)?;
|
||||||
|
|
||||||
|
println!("{contents}");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@@ -1,12 +1,12 @@
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use isahc::{ReadResponseExt, RequestExt};
|
|
||||||
use isahc::http::StatusCode;
|
use isahc::http::StatusCode;
|
||||||
|
use isahc::{ReadResponseExt, RequestExt};
|
||||||
use rsa::pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey, LineEnding};
|
use rsa::pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey, LineEnding};
|
||||||
use rsa::pkcs8::EncodePublicKey;
|
use rsa::pkcs8::EncodePublicKey;
|
||||||
use rsa::RsaPrivateKey;
|
use rsa::RsaPrivateKey;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{BASE_URL, BunqClient, deserialize_retarded_response, sign};
|
use crate::{deserialize_retarded_response, sign, BunqClient, BASE_URL};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default)]
|
#[derive(Serialize, Deserialize, Default)]
|
||||||
struct AppState {
|
struct AppState {
|
||||||
@@ -22,11 +22,17 @@ pub struct BunqConfig {
|
|||||||
|
|
||||||
impl BunqConfig {
|
impl BunqConfig {
|
||||||
pub fn load() -> anyhow::Result<BunqConfig> {
|
pub fn load() -> anyhow::Result<BunqConfig> {
|
||||||
println!("Loading config file from {}", confy::get_configuration_file_path("bunq-rs", "bunq-rs")?.to_string_lossy());
|
println!(
|
||||||
|
"Loading config file from {}",
|
||||||
|
confy::get_configuration_file_path("bunq-rs", "bunq-rs")?.to_string_lossy()
|
||||||
|
);
|
||||||
Ok(confy::load("bunq-rs", "bunq-rs")?)
|
Ok(confy::load("bunq-rs", "bunq-rs")?)
|
||||||
}
|
}
|
||||||
pub fn save(&self) -> anyhow::Result<()> {
|
pub fn save(&self) -> anyhow::Result<()> {
|
||||||
println!("Storing config file in {}", confy::get_configuration_file_path("bunq-rs", None)?.to_string_lossy());
|
println!(
|
||||||
|
"Storing config file in {}",
|
||||||
|
confy::get_configuration_file_path("bunq-rs", None)?.to_string_lossy()
|
||||||
|
);
|
||||||
confy::store("bunq-rs", "bunq-rs", self)?;
|
confy::store("bunq-rs", "bunq-rs", self)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -41,7 +47,9 @@ impl BunqConfig {
|
|||||||
let bits = 2048;
|
let bits = 2048;
|
||||||
let keypair = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
|
let keypair = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
|
||||||
|
|
||||||
let pem_public = keypair.to_public_key().to_public_key_pem(LineEnding::CRLF)?;
|
let pem_public = keypair
|
||||||
|
.to_public_key()
|
||||||
|
.to_public_key_pem(LineEnding::CRLF)?;
|
||||||
|
|
||||||
let body = Installation {
|
let body = Installation {
|
||||||
client_public_key: &pem_public,
|
client_public_key: &pem_public,
|
||||||
@@ -50,7 +58,7 @@ impl BunqConfig {
|
|||||||
format!("{}/v1/installation", BASE_URL),
|
format!("{}/v1/installation", BASE_URL),
|
||||||
serde_json::to_string(&body)?,
|
serde_json::to_string(&body)?,
|
||||||
)?
|
)?
|
||||||
.text()?;
|
.text()?;
|
||||||
let response: InstallationResponse = deserialize_retarded_response(&response)?.response;
|
let response: InstallationResponse = deserialize_retarded_response(&response)?.response;
|
||||||
let token = response.token.token;
|
let token = response.token.token;
|
||||||
|
|
||||||
@@ -72,7 +80,10 @@ impl BunqConfig {
|
|||||||
return Err(anyhow!(response_text));
|
return Err(anyhow!(response_text));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.state = Some(AppState { pem_private: keypair.to_pkcs1_pem(LineEnding::CRLF)?.to_string(), token });
|
self.state = Some(AppState {
|
||||||
|
pem_private: keypair.to_pkcs1_pem(LineEnding::CRLF)?.to_string(),
|
||||||
|
token,
|
||||||
|
});
|
||||||
self.save()?;
|
self.save()?;
|
||||||
|
|
||||||
keypair
|
keypair
|
||||||
|
23
src/lib.rs
23
src/lib.rs
@@ -1,12 +1,12 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use rsa::pkcs1v15::SigningKey;
|
use rsa::pkcs1v15::SigningKey;
|
||||||
use rsa::RsaPrivateKey;
|
|
||||||
use rsa::sha2::Sha256;
|
use rsa::sha2::Sha256;
|
||||||
use rsa::signature::RandomizedSigner;
|
use rsa::signature::RandomizedSigner;
|
||||||
|
use rsa::RsaPrivateKey;
|
||||||
use serde::{de::DeserializeOwned, Deserialize};
|
use serde::{de::DeserializeOwned, Deserialize};
|
||||||
|
|
||||||
pub use config::BunqConfig;
|
pub use config::BunqConfig;
|
||||||
pub use monetary_account::MonetaryAccount;
|
pub use monetary_account::{CsvType, MonetaryAccount, StatementFormat};
|
||||||
pub use payment::Payment;
|
pub use payment::Payment;
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
@@ -38,6 +38,23 @@ impl BunqClient {
|
|||||||
) -> anyhow::Result<Vec<Payment>> {
|
) -> anyhow::Result<Vec<Payment>> {
|
||||||
payment::get_from_to(self, acc, from, to)
|
payment::get_from_to(self, acc, from, to)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request_statement(
|
||||||
|
&self,
|
||||||
|
acc: &MonetaryAccount,
|
||||||
|
format: StatementFormat,
|
||||||
|
date_start: &str,
|
||||||
|
date_end: &str,
|
||||||
|
) -> Result<i64> {
|
||||||
|
monetary_account::request_statement(self, acc, format, date_start, date_end)
|
||||||
|
}
|
||||||
|
pub fn is_statement_ready(&self, acc: &MonetaryAccount, statement_id: i64) -> Result<bool> {
|
||||||
|
monetary_account::is_statement_ready(self, acc, statement_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn download_statement(&self, acc: &MonetaryAccount, statement_id: i64) -> Result<String> {
|
||||||
|
monetary_account::download_statement(self, acc, statement_id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
@@ -94,7 +111,7 @@ fn deserialize_normal_response<T: DeserializeOwned>(r: &str) -> Result<Response<
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sign(body: &str, key: &RsaPrivateKey) -> Result<String> {
|
fn sign(body: &str, key: &RsaPrivateKey) -> Result<String> {
|
||||||
use base64::prelude::{BASE64_STANDARD, Engine};
|
use base64::prelude::{Engine, BASE64_STANDARD};
|
||||||
|
|
||||||
let signing_key = SigningKey::<Sha256>::new(key.clone());
|
let signing_key = SigningKey::<Sha256>::new(key.clone());
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
|
@@ -1,23 +1,137 @@
|
|||||||
use isahc::{ReadResponseExt, RequestExt};
|
use std::fmt::Display;
|
||||||
use serde::Deserialize;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::{BASE_URL, BunqClient};
|
use anyhow::{anyhow, Result};
|
||||||
|
use isahc::http::StatusCode;
|
||||||
|
use isahc::{ReadResponseExt, RequestExt};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{deserialize_normal_response, sign, BunqClient, BASE_URL};
|
||||||
|
|
||||||
pub(super) fn get(client: &BunqClient) -> anyhow::Result<Vec<MonetaryAccount>> {
|
pub(super) fn get(client: &BunqClient) -> anyhow::Result<Vec<MonetaryAccount>> {
|
||||||
let response = isahc::http::Request::get(format!(
|
let response = isahc::http::Request::get(format!(
|
||||||
"{}/v1/user/{}/monetary-account",
|
"{}/v1/user/{}/monetary-account",
|
||||||
BASE_URL, client.user_id
|
BASE_URL, client.user_id
|
||||||
))
|
))
|
||||||
.header("X-Bunq-Client-Authentication", &client.token)
|
.header("X-Bunq-Client-Authentication", &client.token)
|
||||||
.body(())?
|
.body(())?
|
||||||
.send()?
|
.send()?
|
||||||
.text()?;
|
.text()?;
|
||||||
|
|
||||||
let accounts = crate::deserialize_normal_response::<Vec<MonetaryAccount>>(&response)?;
|
let accounts = crate::deserialize_normal_response::<Vec<MonetaryAccount>>(&response)?;
|
||||||
|
|
||||||
Ok(accounts.response)
|
Ok(accounts.response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn request_statement(
|
||||||
|
client: &BunqClient,
|
||||||
|
account: &MonetaryAccount,
|
||||||
|
format: StatementFormat,
|
||||||
|
start: &str,
|
||||||
|
end: &str,
|
||||||
|
) -> Result<i64> {
|
||||||
|
let statement_request = CreateStatementRequest {
|
||||||
|
statement_format: &format.to_string(),
|
||||||
|
regional_format: match format {
|
||||||
|
StatementFormat::CSV(CsvType::Comma) => "UK_US",
|
||||||
|
StatementFormat::CSV(CsvType::Semicolon) => "EUROPEAN",
|
||||||
|
_ => "",
|
||||||
|
},
|
||||||
|
date_start: start,
|
||||||
|
date_end: end,
|
||||||
|
include_attachment: match format {
|
||||||
|
StatementFormat::PDF(v) => v,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = serde_json::to_string(&statement_request)?;
|
||||||
|
let sig = sign(&body, &client.keypair)?;
|
||||||
|
|
||||||
|
let request_url = format!(
|
||||||
|
"{}/v1/user/{}/monetary-account/{}/customer-statement",
|
||||||
|
BASE_URL,
|
||||||
|
client.user_id,
|
||||||
|
account.id()
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut response = isahc::http::Request::post(request_url)
|
||||||
|
.header("X-Bunq-Client-Authentication", &client.token)
|
||||||
|
.header("X-Bunq-Client-Signature", &sig)
|
||||||
|
.body(body)?
|
||||||
|
.send()?;
|
||||||
|
|
||||||
|
if response.status() != StatusCode::OK {
|
||||||
|
return Err(anyhow!(response.text()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
let response_body = response.text()?;
|
||||||
|
|
||||||
|
//let response_body = r#"{"Response":[{"Id":{"id":4203007}}]}"#;
|
||||||
|
//println!("{response_body}");
|
||||||
|
|
||||||
|
let r = deserialize_normal_response::<CreateStatementResponse>(&response_body)?.response;
|
||||||
|
|
||||||
|
let statement_id = r.id.id.id;
|
||||||
|
|
||||||
|
Ok(statement_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn is_statement_ready(
|
||||||
|
client: &BunqClient,
|
||||||
|
account: &MonetaryAccount,
|
||||||
|
statement_id: i64,
|
||||||
|
) -> Result<bool> {
|
||||||
|
let url = format!(
|
||||||
|
"{}/v1/user/{}/monetary-account/{}/customer-statement/{}",
|
||||||
|
BASE_URL,
|
||||||
|
client.user_id,
|
||||||
|
account.id(),
|
||||||
|
statement_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut response = isahc::http::Request::get(url)
|
||||||
|
.header("X-Bunq-Client-Authentication", &client.token)
|
||||||
|
.body(())?
|
||||||
|
.send()?;
|
||||||
|
|
||||||
|
let body = response.text()?;
|
||||||
|
|
||||||
|
let statement = deserialize_normal_response::<Vec<CustomerStatementWrapper>>(&body)?
|
||||||
|
.response
|
||||||
|
.iter()
|
||||||
|
.map(|v| v.customer_statement.clone())
|
||||||
|
.take(1)
|
||||||
|
.collect::<Vec<CustomerStatement>>()
|
||||||
|
.pop()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
//let statement = statements.first().unwrap();
|
||||||
|
|
||||||
|
Ok(statement.status == "COMPLETED")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn download_statement(
|
||||||
|
client: &BunqClient,
|
||||||
|
account: &MonetaryAccount,
|
||||||
|
id: i64,
|
||||||
|
) -> Result<String> {
|
||||||
|
let content_url = format!(
|
||||||
|
"{}/v1/user/{}/monetary-account/{}/customer-statement/{}/content",
|
||||||
|
BASE_URL,
|
||||||
|
client.user_id,
|
||||||
|
account.id(),
|
||||||
|
id
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut response = isahc::http::Request::get(content_url)
|
||||||
|
.header("X-Bunq-Client-Authentication", &client.token)
|
||||||
|
.body(())?
|
||||||
|
.send()?;
|
||||||
|
|
||||||
|
Ok(response.text()?)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
#[serde(rename_all = "PascalCase")]
|
#[serde(rename_all = "PascalCase")]
|
||||||
pub enum MonetaryAccount {
|
pub enum MonetaryAccount {
|
||||||
@@ -25,6 +139,15 @@ pub enum MonetaryAccount {
|
|||||||
MonetaryAccountSavings(MonetaryAccountSavings),
|
MonetaryAccountSavings(MonetaryAccountSavings),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MonetaryAccount {
|
||||||
|
pub fn id(&self) -> i64 {
|
||||||
|
match &self {
|
||||||
|
MonetaryAccount::MonetaryAccountBank(b) => b.id,
|
||||||
|
MonetaryAccount::MonetaryAccountSavings(s) => s.id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug)]
|
#[derive(Deserialize, Debug)]
|
||||||
pub struct MonetaryAccountBank {
|
pub struct MonetaryAccountBank {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
@@ -36,3 +159,77 @@ pub struct MonetaryAccountSavings {
|
|||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub description: String,
|
pub description: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum CsvType {
|
||||||
|
Comma,
|
||||||
|
Semicolon,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum StatementFormat {
|
||||||
|
CSV(CsvType),
|
||||||
|
MT940,
|
||||||
|
PDF(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for StatementFormat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let str = match self {
|
||||||
|
StatementFormat::CSV(_) => "CSV",
|
||||||
|
StatementFormat::MT940 => "MT940",
|
||||||
|
StatementFormat::PDF(_) => "PDF",
|
||||||
|
};
|
||||||
|
write!(f, "{}", str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for StatementFormat {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
match s.to_ascii_uppercase().as_str() {
|
||||||
|
"CSV" => Ok(StatementFormat::CSV(CsvType::Semicolon)),
|
||||||
|
"MT940" => Ok(StatementFormat::MT940),
|
||||||
|
"PDF" => Ok(StatementFormat::PDF(false)),
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
struct CustomerStatementWrapper {
|
||||||
|
customer_statement: CustomerStatement,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
pub struct CustomerStatement {
|
||||||
|
pub id: i64,
|
||||||
|
status: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct CreateStatementRequest<'a> {
|
||||||
|
statement_format: &'a str,
|
||||||
|
date_start: &'a str,
|
||||||
|
date_end: &'a str,
|
||||||
|
regional_format: &'a str,
|
||||||
|
include_attachment: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
struct CreateStatementResponse {
|
||||||
|
id: Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
//#[derive(Deserialize, Debug)]
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
struct Id {
|
||||||
|
id: Id2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Debug)]
|
||||||
|
struct Id2 {
|
||||||
|
id: i64,
|
||||||
|
}
|
||||||
|
@@ -2,13 +2,14 @@ use anyhow::Result;
|
|||||||
use isahc::{ReadResponseExt, RequestExt};
|
use isahc::{ReadResponseExt, RequestExt};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{BASE_URL, BunqClient, MonetaryAccount, Pagination, Response};
|
use crate::{BunqClient, MonetaryAccount, Pagination, Response, BASE_URL};
|
||||||
|
|
||||||
pub(super) fn get_from_to(client: &BunqClient,
|
pub(super) fn get_from_to(
|
||||||
acc: &MonetaryAccount,
|
client: &BunqClient,
|
||||||
from: Option<i64>,
|
acc: &MonetaryAccount,
|
||||||
to: Option<i64>) -> Result<Vec<Payment>>
|
from: Option<i64>,
|
||||||
{
|
to: Option<i64>,
|
||||||
|
) -> Result<Vec<Payment>> {
|
||||||
let next_page = |url: &str| -> Result<(_, _)> {
|
let next_page = |url: &str| -> Result<(_, _)> {
|
||||||
let response = isahc::http::Request::get(url)
|
let response = isahc::http::Request::get(url)
|
||||||
.header("X-Bunq-Client-Authentication", &client.token)
|
.header("X-Bunq-Client-Authentication", &client.token)
|
||||||
@@ -46,9 +47,9 @@ pub(super) fn get_from_to(client: &BunqClient,
|
|||||||
all.append(&mut payments);
|
all.append(&mut payments);
|
||||||
dbg!(&pag);
|
dbg!(&pag);
|
||||||
if let Some(Pagination {
|
if let Some(Pagination {
|
||||||
older_url: Some(older_url),
|
older_url: Some(older_url),
|
||||||
..
|
..
|
||||||
}) = pag
|
}) = pag
|
||||||
{
|
{
|
||||||
if let (Some(latest), Some(from)) = (all.last(), from) {
|
if let (Some(latest), Some(from)) = (all.last(), from) {
|
||||||
if latest.id <= from {
|
if latest.id <= from {
|
||||||
|
Reference in New Issue
Block a user