feat(config): proxy
Make HTTP client proxy configurable for both paheko and helloasso
This commit is contained in:
parent
19117e2a19
commit
40c41fd930
4 changed files with 148 additions and 69 deletions
7
TODO.md
7
TODO.md
|
@ -20,9 +20,14 @@ we should have created our own platform so people can register and pay later (ei
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
- more configuration options
|
- more configuration options
|
||||||
- configurable proxy
|
|
||||||
- summary of the operations at the end of run
|
- summary of the operations at the end of run
|
||||||
- how many users were added, muted?
|
- how many users were added, muted?
|
||||||
- conjoined user: add attached member to paheko
|
- conjoined user: add attached member to paheko
|
||||||
- "Membre lié"
|
- "Membre lié"
|
||||||
- is this kind of thing even accessible on the API-level ?
|
- is this kind of thing even accessible on the API-level ?
|
||||||
|
|
||||||
|
- better error handling & report to the user
|
||||||
|
- handle import error
|
||||||
|
- handle name of the service or service fee not found
|
||||||
|
|
||||||
|
- BUG: quand l'utilisateur est déjà créé, ya un problème d'ID, le user summary n'a pas le bon id, il faut le populer depuis ce qu'on a déjà fetch
|
||||||
|
|
|
@ -19,11 +19,23 @@ struct WebSession {
|
||||||
jwt: String
|
jwt: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
#[fully_pub]
|
#[fully_pub]
|
||||||
struct Client {
|
struct ClientConfig {
|
||||||
client: reqwest::Client,
|
|
||||||
base_url: Url,
|
base_url: Url,
|
||||||
|
proxy: Option<reqwest::Proxy>,
|
||||||
|
user_agent: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ClientConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
ClientConfig {
|
||||||
|
proxy: None,
|
||||||
|
base_url: Url::parse("https://api.helloasso.com/v5/") // the traling slash is important
|
||||||
|
.expect("Expected valid helloasso API base URL"),
|
||||||
|
user_agent: "".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Debug)]
|
||||||
|
@ -33,31 +45,47 @@ struct LoginPayload {
|
||||||
password: String
|
password: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[fully_pub]
|
||||||
|
struct Client {
|
||||||
|
client: reqwest::Client,
|
||||||
|
config: ClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Client {
|
impl Default for Client {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let base_config: ClientConfig = Default::default();
|
||||||
Client {
|
Client {
|
||||||
client: Client::get_base_client_builder()
|
client: Client::get_base_client_builder(&base_config)
|
||||||
.build()
|
.build()
|
||||||
.expect("reqwest client to be built"),
|
.expect("Expected reqwest client to be built"),
|
||||||
base_url: Url::parse("https://api.helloasso.com/v5/")
|
config: base_config
|
||||||
.expect("Valid helloasso API base URL")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
|
pub fn new(config: ClientConfig) -> Client {
|
||||||
|
Client {
|
||||||
|
client: Client::get_base_client_builder(&config)
|
||||||
|
.build()
|
||||||
|
.expect("Expected reqwest client to be built"),
|
||||||
|
config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_base_client_builder() -> reqwest::ClientBuilder {
|
fn get_base_client_builder(config: &ClientConfig) -> reqwest::ClientBuilder {
|
||||||
let mut default_headers = reqwest::header::HeaderMap::new();
|
let mut default_headers = reqwest::header::HeaderMap::new();
|
||||||
default_headers.insert("Accept", "application/json".parse().unwrap());
|
default_headers.insert("Accept", "application/json".parse().unwrap());
|
||||||
// decoy user agent
|
default_headers.insert("User-Agent", config.user_agent.parse().unwrap());
|
||||||
default_headers.insert("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/112.0".parse().unwrap());
|
|
||||||
|
|
||||||
// TODO: configurable proxy
|
let mut builder = reqwest::Client::builder()
|
||||||
// let proxy = reqwest::Proxy::https("https://localhost:8999").unwrap();
|
.default_headers(default_headers);
|
||||||
reqwest::Client::builder()
|
if let Some(proxy) = &config.proxy {
|
||||||
// .proxy(proxy)
|
builder = builder.proxy(proxy.clone());
|
||||||
.default_headers(default_headers)
|
}
|
||||||
|
builder
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login(&mut self, payload: LoginPayload) -> Result<AuthentifiedClient> {
|
pub async fn login(&mut self, payload: LoginPayload) -> Result<AuthentifiedClient> {
|
||||||
|
@ -67,12 +95,12 @@ impl Client {
|
||||||
"https://auth.helloasso.com".parse().expect("Header value to be OK")
|
"https://auth.helloasso.com".parse().expect("Header value to be OK")
|
||||||
);
|
);
|
||||||
|
|
||||||
let res = self.client.get(self.base_url.join("auth/antiforgerytoken")?)
|
let res = self.client.get(self.config.base_url.join("auth/antiforgerytoken")?)
|
||||||
.headers(login_commons_headers.clone())
|
.headers(login_commons_headers.clone())
|
||||||
.send().await?;
|
.send().await?;
|
||||||
let antiforgerytoken: String = res.json().await?;
|
let antiforgerytoken: String = res.json().await?;
|
||||||
|
|
||||||
let res = self.client.post(self.base_url.join("auth/login")?)
|
let res = self.client.post(self.config.base_url.join("auth/login")?)
|
||||||
.json(&payload)
|
.json(&payload)
|
||||||
.headers(login_commons_headers.clone())
|
.headers(login_commons_headers.clone())
|
||||||
.header("x-csrf-token", antiforgerytoken)
|
.header("x-csrf-token", antiforgerytoken)
|
||||||
|
@ -107,7 +135,7 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authentified_client(&self, session: WebSession) -> AuthentifiedClient {
|
pub fn authentified_client(&self, session: WebSession) -> AuthentifiedClient {
|
||||||
AuthentifiedClient::new(self.base_url.clone(), session)
|
AuthentifiedClient::new(self.config.clone(), session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +144,7 @@ impl Client {
|
||||||
struct AuthentifiedClient {
|
struct AuthentifiedClient {
|
||||||
session: WebSession,
|
session: WebSession,
|
||||||
client: reqwest::Client,
|
client: reqwest::Client,
|
||||||
base_url: Url
|
config: ClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
@ -167,30 +195,30 @@ struct UserDetails {
|
||||||
|
|
||||||
impl AuthentifiedClient {
|
impl AuthentifiedClient {
|
||||||
/// each time we need to change the token, we will need to rebuild the client
|
/// each time we need to change the token, we will need to rebuild the client
|
||||||
pub fn new(base_url: Url, session: WebSession) -> Self {
|
pub fn new(config: ClientConfig, session: WebSession) -> Self {
|
||||||
let mut auth_headers = reqwest::header::HeaderMap::new();
|
let mut auth_headers = reqwest::header::HeaderMap::new();
|
||||||
auth_headers.insert("Authorization", format!("Bearer {}", session.jwt).parse().unwrap());
|
auth_headers.insert("Authorization", format!("Bearer {}", session.jwt).parse().unwrap());
|
||||||
|
|
||||||
AuthentifiedClient {
|
AuthentifiedClient {
|
||||||
base_url,
|
|
||||||
session,
|
session,
|
||||||
client: Client::get_base_client_builder()
|
client: Client::get_base_client_builder(&config)
|
||||||
.default_headers(auth_headers)
|
.default_headers(auth_headers)
|
||||||
.build()
|
.build()
|
||||||
.expect("reqwest client to be built")
|
.expect("reqwest client to be built"),
|
||||||
|
config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn verify_auth(&self) -> Result<bool> {
|
pub async fn verify_auth(&self) -> Result<bool> {
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.get(self.base_url.join("agg/user")?)
|
.get(self.config.base_url.join("agg/user")?)
|
||||||
.send().await?;
|
.send().await?;
|
||||||
Ok(res.status() == 200)
|
Ok(res.status() == 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user_details(&self) -> Result<serde_json::Value> {
|
pub async fn get_user_details(&self) -> Result<serde_json::Value> {
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.get(self.base_url.join("agg/user")?)
|
.get(self.config.base_url.join("agg/user")?)
|
||||||
.send().await?;
|
.send().await?;
|
||||||
if res.status() != 200 {
|
if res.status() != 200 {
|
||||||
return Err(APIClientError::InvalidStatusCode.into());
|
return Err(APIClientError::InvalidStatusCode.into());
|
||||||
|
@ -202,7 +230,7 @@ impl AuthentifiedClient {
|
||||||
|
|
||||||
async fn simple_fetch(&self, path: String) -> Result<serde_json::Value> {
|
async fn simple_fetch(&self, path: String) -> Result<serde_json::Value> {
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.get(self.base_url.join(path.as_str())?)
|
.get(self.config.base_url.join(path.as_str())?)
|
||||||
.send().await?;
|
.send().await?;
|
||||||
if res.status() != 200 {
|
if res.status() != 200 {
|
||||||
return Err(APIClientError::InvalidStatusCode.into());
|
return Err(APIClientError::InvalidStatusCode.into());
|
||||||
|
@ -217,7 +245,7 @@ impl AuthentifiedClient {
|
||||||
let mut continuation_token: Option<String> = None;
|
let mut continuation_token: Option<String> = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let mut url = self.base_url.join(path.as_str())?;
|
let mut url = self.config.base_url.join(path.as_str())?;
|
||||||
if let Some(token) = &continuation_token {
|
if let Some(token) = &continuation_token {
|
||||||
url.query_pairs_mut().append_pair("continuationToken", token);
|
url.query_pairs_mut().append_pair("continuationToken", token);
|
||||||
}
|
}
|
||||||
|
|
35
src/main.rs
35
src/main.rs
|
@ -3,22 +3,26 @@ mod paheko;
|
||||||
mod helloasso;
|
mod helloasso;
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result, anyhow};
|
||||||
use chrono::prelude::{NaiveDate, DateTime, Utc, Datelike};
|
use chrono::prelude::{NaiveDate, DateTime, Utc, Datelike};
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
use utils::generate_id;
|
use utils::generate_id;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
/// permanent config to store long-term config
|
/// permanent config to store long-term config
|
||||||
/// used to ingest env settings
|
/// used to ingest env settings
|
||||||
/// config loaded from env variables
|
/// config loaded from env variables
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
struct Config {
|
struct Config {
|
||||||
|
helloasso_proxy: Option<String>,
|
||||||
helloasso_email: String,
|
helloasso_email: String,
|
||||||
helloasso_password: String,
|
helloasso_password: String,
|
||||||
|
paheko_proxy: Option<String>,
|
||||||
paheko_base_url: String,
|
paheko_base_url: String,
|
||||||
paheko_client_id: String,
|
paheko_client_id: String,
|
||||||
paheko_client_secret: String,
|
paheko_client_secret: String,
|
||||||
|
paheko_accounting_year_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
// start user cache management
|
// start user cache management
|
||||||
|
@ -40,6 +44,7 @@ enum LoadError {
|
||||||
FailedToWrite
|
FailedToWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const APP_USER_AGENT: &str = "helloasso_paheko_adapter";
|
||||||
|
|
||||||
fn write_user_cache(cache: &UserCache) -> Result<(), LoadError> {
|
fn write_user_cache(cache: &UserCache) -> Result<(), LoadError> {
|
||||||
let xdg_dirs = xdg::BaseDirectories::with_prefix(env!("CARGO_PKG_NAME"))
|
let xdg_dirs = xdg::BaseDirectories::with_prefix(env!("CARGO_PKG_NAME"))
|
||||||
|
@ -175,6 +180,14 @@ fn parse_and_get_birthday_year(raw_date: String) -> Option<u32> {
|
||||||
d.year().try_into().ok()
|
d.year().try_into().ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_proxy_from_url(proxy_url: Option<String>) -> Result<Option<reqwest::Proxy>> {
|
||||||
|
Ok(match proxy_url {
|
||||||
|
Some(p) => Some(reqwest::Proxy::all(&p)
|
||||||
|
.context("Expected to build Proxy from paheko_proxy config value")?),
|
||||||
|
None => None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async fn launch_adapter() -> Result<()> {
|
async fn launch_adapter() -> Result<()> {
|
||||||
dotenvy::dotenv()?;
|
dotenvy::dotenv()?;
|
||||||
|
|
||||||
|
@ -182,7 +195,14 @@ async fn launch_adapter() -> Result<()> {
|
||||||
|
|
||||||
let mut user_cache = load_user_cache().context("Failed to load user cache")?;
|
let mut user_cache = load_user_cache().context("Failed to load user cache")?;
|
||||||
|
|
||||||
let mut paheko_client: paheko::Client = paheko::Client::new(config.paheko_base_url);
|
if !&config.paheko_base_url.ends_with("/") {
|
||||||
|
return Err(anyhow!("Invalid paheko base_url, it must end with a slash"))
|
||||||
|
}
|
||||||
|
let mut paheko_client: paheko::Client = paheko::Client::new(paheko::ClientConfig {
|
||||||
|
base_url: Url::parse(&config.paheko_base_url).expect("Expected paheko base url to be a valid URL"),
|
||||||
|
proxy: get_proxy_from_url(config.paheko_proxy)?,
|
||||||
|
user_agent: APP_USER_AGENT.to_string()
|
||||||
|
});
|
||||||
|
|
||||||
let paheko_credentials = paheko::Credentials {
|
let paheko_credentials = paheko::Credentials {
|
||||||
client_id: config.paheko_client_id,
|
client_id: config.paheko_client_id,
|
||||||
|
@ -190,8 +210,12 @@ async fn launch_adapter() -> Result<()> {
|
||||||
};
|
};
|
||||||
let paheko_client: paheko::AuthentifiedClient = paheko_client.login(paheko_credentials).await?;
|
let paheko_client: paheko::AuthentifiedClient = paheko_client.login(paheko_credentials).await?;
|
||||||
|
|
||||||
|
let mut ha_client: helloasso::Client = helloasso::Client::new(helloasso::ClientConfig {
|
||||||
let mut ha_client: helloasso::Client = Default::default();
|
base_url: Url::parse("https://api.helloasso.com/v5/")
|
||||||
|
.expect("Expected valid helloasso API base URL"),
|
||||||
|
proxy: get_proxy_from_url(config.helloasso_proxy)?,
|
||||||
|
user_agent: "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/112.0".to_string()
|
||||||
|
});
|
||||||
|
|
||||||
let login_payload = helloasso::LoginPayload {
|
let login_payload = helloasso::LoginPayload {
|
||||||
email: config.helloasso_email,
|
email: config.helloasso_email,
|
||||||
|
@ -378,6 +402,7 @@ async fn launch_adapter() -> Result<()> {
|
||||||
|
|
||||||
// add transaction
|
// add transaction
|
||||||
let transaction = paheko::SimpleTransaction {
|
let transaction = paheko::SimpleTransaction {
|
||||||
|
accounting_year: utils::Id(config.paheko_accounting_year_id),
|
||||||
// TODO: make the label template configurable
|
// TODO: make the label template configurable
|
||||||
label: format!("Adhésion {:?} via HelloAsso", pk_membership.mode_name),
|
label: format!("Adhésion {:?} via HelloAsso", pk_membership.mode_name),
|
||||||
amount: pk_membership.payed_amount,
|
amount: pk_membership.payed_amount,
|
||||||
|
@ -392,7 +417,7 @@ async fn launch_adapter() -> Result<()> {
|
||||||
linked_services: pk_user_service_registrations.iter().map(|x| x.id.clone()).collect()
|
linked_services: pk_user_service_registrations.iter().map(|x| x.id.clone()).collect()
|
||||||
};
|
};
|
||||||
let _ = paheko_client.register_transaction(transaction)
|
let _ = paheko_client.register_transaction(transaction)
|
||||||
.await.context("Expected to create new paheko transaction");
|
.await.context("Expected to create new paheko transaction")?;
|
||||||
eprintln!(" Created paheko transaction");
|
eprintln!(" Created paheko transaction");
|
||||||
|
|
||||||
pk_memberships.push(pk_membership);
|
pk_memberships.push(pk_membership);
|
||||||
|
|
|
@ -92,17 +92,10 @@ struct SimpleTransaction {
|
||||||
debit_account_code: String,
|
debit_account_code: String,
|
||||||
reference: String,
|
reference: String,
|
||||||
linked_users: Vec<Id>,
|
linked_users: Vec<Id>,
|
||||||
linked_services: Vec<Id>
|
linked_services: Vec<Id>,
|
||||||
|
accounting_year: Id
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[fully_pub]
|
|
||||||
struct Client {
|
|
||||||
client: reqwest::Client,
|
|
||||||
base_url: Url,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
enum APIClientError {
|
enum APIClientError {
|
||||||
#[error("Received non-normal status code from API")]
|
#[error("Received non-normal status code from API")]
|
||||||
|
@ -116,15 +109,40 @@ struct Credentials {
|
||||||
client_secret: String
|
client_secret: String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
#[fully_pub]
|
||||||
|
struct ClientConfig {
|
||||||
|
base_url: Url,
|
||||||
|
proxy: Option<reqwest::Proxy>,
|
||||||
|
user_agent: String
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ClientConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
ClientConfig {
|
||||||
|
proxy: None,
|
||||||
|
base_url: Url::parse("https://paheko.example.org/api/") // the traling slash is important
|
||||||
|
.expect("Expected valid paheko API base URL"),
|
||||||
|
user_agent: "".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[fully_pub]
|
||||||
|
struct Client {
|
||||||
|
client: reqwest::Client,
|
||||||
|
config: ClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Client {
|
impl Default for Client {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let base_config: ClientConfig = Default::default();
|
||||||
Client {
|
Client {
|
||||||
client: Client::get_base_client_builder()
|
client: Client::get_base_client_builder(&base_config)
|
||||||
.build()
|
.build()
|
||||||
.expect("Expected reqwest client to be built"),
|
.expect("Expected reqwest client to be built"),
|
||||||
base_url: Url::parse("https://paheko.etoiledebethleem.fr/api/") // the traling slash is important
|
config: base_config
|
||||||
.expect("Expected valid paheko API base URL")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,25 +161,26 @@ fn build_auth_headers(credentials: &Credentials) -> reqwest::header::HeaderMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(base_url: String) -> Client {
|
pub fn new(config: ClientConfig) -> Client {
|
||||||
Client {
|
Client {
|
||||||
client: Client::get_base_client_builder()
|
client: Client::get_base_client_builder(&config)
|
||||||
.build()
|
.build()
|
||||||
.expect("Expected reqwest client to be built"),
|
.expect("Expected reqwest client to be built"),
|
||||||
base_url: Url::parse(&base_url) // the traling slash is important
|
config
|
||||||
.expect("Expected valid paheko API base URL")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_base_client_builder() -> reqwest::ClientBuilder {
|
fn get_base_client_builder(config: &ClientConfig) -> reqwest::ClientBuilder {
|
||||||
let mut default_headers = reqwest::header::HeaderMap::new();
|
let mut default_headers = reqwest::header::HeaderMap::new();
|
||||||
default_headers.insert("Accept", "application/json".parse().unwrap());
|
default_headers.insert("Accept", "application/json".parse().unwrap());
|
||||||
default_headers.insert("User-Agent", "helloasso_paheko_adapter".parse().unwrap());
|
default_headers.insert("User-Agent", config.user_agent.parse().unwrap());
|
||||||
|
|
||||||
// let proxy = reqwest::Proxy::http("http://localhost:8998").unwrap();
|
let mut builder = reqwest::Client::builder()
|
||||||
reqwest::Client::builder()
|
.default_headers(default_headers);
|
||||||
// .proxy(proxy)
|
if let Some(proxy) = &config.proxy {
|
||||||
.default_headers(default_headers)
|
builder = builder.proxy(proxy.clone());
|
||||||
|
}
|
||||||
|
builder
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login(&mut self, credentials: Credentials) -> Result<AuthentifiedClient> {
|
pub async fn login(&mut self, credentials: Credentials) -> Result<AuthentifiedClient> {
|
||||||
|
@ -181,16 +200,16 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authentified_client(&self, credentials: Credentials) -> AuthentifiedClient {
|
pub fn authentified_client(&self, credentials: Credentials) -> AuthentifiedClient {
|
||||||
AuthentifiedClient::new(self.base_url.clone(), credentials)
|
AuthentifiedClient::new(self.config.clone(), credentials)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AuthentifiedClient {
|
pub struct AuthentifiedClient {
|
||||||
credentials: Credentials,
|
_credentials: Credentials,
|
||||||
client: reqwest::Client,
|
client: reqwest::Client,
|
||||||
base_url: Url
|
config: ClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// SELECT id,nom AS first_name,last_name,email,external_custom_data FROM users LIMIT 5;
|
// SELECT id,nom AS first_name,last_name,email,external_custom_data FROM users LIMIT 5;
|
||||||
|
@ -225,14 +244,14 @@ struct UserServiceRegistration {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthentifiedClient {
|
impl AuthentifiedClient {
|
||||||
pub fn new(base_url: Url, credentials: Credentials) -> Self {
|
pub fn new(config: ClientConfig, credentials: Credentials) -> Self {
|
||||||
AuthentifiedClient {
|
AuthentifiedClient {
|
||||||
client: Client::get_base_client_builder()
|
client: Client::get_base_client_builder(&config)
|
||||||
.default_headers(build_auth_headers(&credentials))
|
.default_headers(build_auth_headers(&credentials))
|
||||||
.build()
|
.build()
|
||||||
.expect("Expect client to be built"),
|
.expect("Expect client to be built"),
|
||||||
credentials,
|
_credentials: credentials,
|
||||||
base_url
|
config
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,7 +261,7 @@ impl AuthentifiedClient {
|
||||||
sql: String
|
sql: String
|
||||||
}
|
}
|
||||||
let payload = Payload { sql: query };
|
let payload = Payload { sql: query };
|
||||||
let path = self.base_url.join("sql")?;
|
let path = self.config.base_url.join("sql")?;
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.post(path)
|
.post(path)
|
||||||
.json(&payload)
|
.json(&payload)
|
||||||
|
@ -329,7 +348,7 @@ impl AuthentifiedClient {
|
||||||
.part("file", part);
|
.part("file", part);
|
||||||
|
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.post(self.base_url.join("user/import/")?)
|
.post(self.config.base_url.join("user/import/")?)
|
||||||
.multipart(form)
|
.multipart(form)
|
||||||
.send().await?;
|
.send().await?;
|
||||||
|
|
||||||
|
@ -377,7 +396,7 @@ impl AuthentifiedClient {
|
||||||
.part("file", part);
|
.part("file", part);
|
||||||
|
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.post(self.base_url.join("services/subscriptions/import")?)
|
.post(self.config.base_url.join("services/subscriptions/import")?)
|
||||||
.multipart(form)
|
.multipart(form)
|
||||||
.send().await?;
|
.send().await?;
|
||||||
|
|
||||||
|
@ -395,25 +414,27 @@ impl AuthentifiedClient {
|
||||||
use reqwest::multipart::Form;
|
use reqwest::multipart::Form;
|
||||||
|
|
||||||
let mut form = Form::new()
|
let mut form = Form::new()
|
||||||
.text("id_year", "1")
|
.text("id_year", transaction.accounting_year.to_string())
|
||||||
.text("label", transaction.label)
|
.text("label", transaction.label)
|
||||||
.text("date", transaction.inception_time.format("%d/%m/%Y").to_string())
|
.text("date", transaction.inception_time.format("%d/%m/%Y").to_string())
|
||||||
.text("type", Into::<String>::into(transaction.kind))
|
.text("type", Into::<String>::into(transaction.kind))
|
||||||
.text("amount", format!("{}", transaction.amount))
|
.text("amount", format!("{}", transaction.amount))
|
||||||
.text("debit", transaction.debit_account_code)
|
.text("debit", transaction.debit_account_code)
|
||||||
.text("credit", transaction.credit_account_code)
|
.text("credit", transaction.credit_account_code)
|
||||||
|
// "Numéro pièce comptable" enregistré au niveau de la transaction
|
||||||
.text("reference", transaction.reference)
|
.text("reference", transaction.reference)
|
||||||
;
|
;
|
||||||
|
|
||||||
for linked_id in transaction.linked_users {
|
for linked_id in transaction.linked_users {
|
||||||
form = form.text("linked_users[]", format!("{}", linked_id.0));
|
form = form.text("linked_users[]", format!("{}", linked_id.0));
|
||||||
}
|
}
|
||||||
|
// only possible with paheko fork
|
||||||
for linked_id in transaction.linked_services {
|
for linked_id in transaction.linked_services {
|
||||||
form = form.text("linked_services[]", format!("{}", linked_id.0));
|
form = form.text("linked_services[]", format!("{}", linked_id.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = self.client
|
let res = self.client
|
||||||
.post(self.base_url.join("accounting/transaction")?)
|
.post(self.config.base_url.join("accounting/transaction")?)
|
||||||
.multipart(form)
|
.multipart(form)
|
||||||
.send().await?;
|
.send().await?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue