helloasso-paheko-adapter/src/sync_helloasso.rs

139 lines
5.6 KiB
Rust
Raw Normal View History

2024-01-13 16:51:06 +00:00
use crate::helloasso;
use crate::paheko;
use crate::{
Config, UserCache,
get_proxy_from_url, get_auth_client_from_cache, parse_and_get_birthday_year, parse_normalize_phone, normalize_str
};
use crate::sync_paheko::{GeneralizedAnswer, sync_paheko};
use anyhow::Result;
use url::Url;
/// rust how to access inner enum value
#[derive(Debug, PartialEq, Clone, Copy)]
enum HelloassoCustomFieldType {
Email,
Address,
PostalCode,
City,
Phone,
Job,
Skills,
Birthday,
LinkedUserFirstName
}
impl TryFrom<&str> for HelloassoCustomFieldType {
type Error = ();
fn try_from(subject: &str) -> Result<Self, Self::Error> {
match subject {
"Prénom conjoint" => Ok(HelloassoCustomFieldType::LinkedUserFirstName),
"ADRESSE" => Ok(HelloassoCustomFieldType::Address),
"CODE POSTAL" => Ok(HelloassoCustomFieldType::PostalCode),
"VILLE" => Ok(HelloassoCustomFieldType::City),
"EMAIL" => Ok(HelloassoCustomFieldType::Email),
"PROFESSION" => Ok(HelloassoCustomFieldType::Job),
"TÉLÉPHONE" => Ok(HelloassoCustomFieldType::Phone),
"DATE DE NAISSANCE" => Ok(HelloassoCustomFieldType::Birthday),
"CENTRE D'INTÉRÊTS / COMPÉTENCES" => Ok(HelloassoCustomFieldType::Skills),
_ => Err(())
}
}
}
fn read_custom_field(form_answer: &helloasso::FormAnswer, custom_field: HelloassoCustomFieldType) -> Option<String> {
// FIXME: compute the type directly at deserialization with serde
form_answer.custom_fields.iter()
.find(|f| HelloassoCustomFieldType::try_from(f.name.as_str()) == Ok(custom_field))
.map(|cf| cf.answer.clone())
}
pub async fn sync_helloasso(paheko_client: &paheko::AuthentifiedClient, config: &Config, user_cache: &mut UserCache) -> Result<()> {
let mut ha_client: helloasso::Client = helloasso::Client::new(helloasso::ClientConfig {
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 {
email: config.helloasso_email.clone(),
password: config.helloasso_password.clone()
};
let auth_client: helloasso::AuthentifiedClient =
get_auth_client_from_cache(user_cache, &mut ha_client, login_payload).await?;
let org = auth_client.organization(&config.helloasso_organization_slug);
let answers = org.get_form_answers(&config.helloasso_form_name).await?;
println!("Got {} answers to the membership form. Processing...", &answers.len());
use email_address::*;
fn choose_email(answer: &helloasso::FormAnswer) -> Option<String> {
read_custom_field(answer, HelloassoCustomFieldType::Email)
.and_then(|x| {
if !EmailAddress::is_valid(&x) {
None
} else {
Some(x)
}
})
.or(Some(answer.payer_user.email.clone()))
}
let mut generalized_answers: Vec<GeneralizedAnswer> = vec![];
for answer in answers {
// eprintln!("Processing answer:");
let email = choose_email(&answer);
// eprintln!(" email: {:?}", email);
let mut generalized_answer = GeneralizedAnswer {
first_name: Some(normalize_str(answer.user.first_name.clone())),
last_name: normalize_str(answer.user.last_name.clone()),
email,
phone: parse_normalize_phone(read_custom_field(&answer, HelloassoCustomFieldType::Phone)),
skills: read_custom_field(&answer, HelloassoCustomFieldType::Skills).map(normalize_str),
address: read_custom_field(&answer, HelloassoCustomFieldType::Address)
.map(normalize_str)
.expect("Expected ha answer to have address"),
postal_code: read_custom_field(&answer, HelloassoCustomFieldType::PostalCode)
.expect("Expected ha answer to have postalcode"),
city: read_custom_field(&answer, HelloassoCustomFieldType::City)
.map(normalize_str)
.expect("Expected ha answer to have city"),
country: answer.payer_user.country.clone().trim()[..=1].to_string(), // we expect country code ISO 3166-1 alpha-2
job: read_custom_field(&answer, HelloassoCustomFieldType::Job).map(normalize_str),
birth_year: read_custom_field(&answer, HelloassoCustomFieldType::Birthday).and_then(parse_and_get_birthday_year),
inception_time: answer.order.inception_time,
reference: format!("HA/{}", answer.id),
donation_amount: 0,
subscription_amount: answer.amount,
membership_mode: serde_json::from_value(serde_json::Value::String(answer.mode.clone()))
.expect("Expected a membership mode to be valid"),
linked_user_first_name: read_custom_field(&answer, HelloassoCustomFieldType::LinkedUserFirstName)
};
// apply custom user override
// this particular answer had duplicate phone and email from another answer
if answer.id == 64756582 {
generalized_answer.email = None;
generalized_answer.phone = None;
}
generalized_answers.push(generalized_answer);
}
println!("Generated GeneralizedAnswers");
sync_paheko(
paheko_client,
config,
user_cache,
generalized_answers,
"512",
"HelloAsso"
).await
}