feat: add membership basic support
This commit is contained in:
parent
7a84f7d3c0
commit
bbdbbbfb8a
4 changed files with 272 additions and 17 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
|||
/target
|
||||
.env
|
||||
log.log
|
||||
tmp
|
||||
|
|
175
Cargo.lock
generated
175
Cargo.lock
generated
|
@ -71,6 +71,15 @@ dependencies = [
|
|||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
|
@ -297,6 +306,15 @@ version = "0.21.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -580,6 +598,12 @@ version = "0.15.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.33"
|
||||
|
@ -1067,6 +1091,15 @@ dependencies = [
|
|||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
|
@ -1125,6 +1158,12 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
|
@ -1156,6 +1195,15 @@ dependencies = [
|
|||
"value-bag",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lru-cache"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
|
@ -1178,6 +1226,12 @@ dependencies = [
|
|||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
|
@ -1216,6 +1270,16 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
|
@ -1250,6 +1314,12 @@ version = "1.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "oncemutex"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d11de466f4a3006fe8a5e7ec84e93b79c70cb992ae0aa0eb631ad2df8abfe2"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
|
@ -1309,10 +1379,12 @@ dependencies = [
|
|||
"clap",
|
||||
"dotenvy",
|
||||
"envy",
|
||||
"phonenumber",
|
||||
"rand 0.8.5",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
"strum 0.25.0",
|
||||
"surf",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
|
@ -1355,6 +1427,27 @@ version = "2.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "phonenumber"
|
||||
version = "0.3.3+8.13.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "635f3e6288e4f01c049d89332a031bd74f25d64b6fb94703ca966e819488cd06"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"either",
|
||||
"fnv",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"quick-xml",
|
||||
"regex",
|
||||
"regex-cache",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"strum 0.24.1",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.3"
|
||||
|
@ -1452,6 +1545,15 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.28.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
|
@ -1541,6 +1643,53 @@ dependencies = [
|
|||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-cache"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f7b62d69743b8b94f353b6b7c3deb4c5582828328bcb8d5fedf214373808793"
|
||||
dependencies = [
|
||||
"lru-cache",
|
||||
"oncemutex",
|
||||
"regex",
|
||||
"regex-syntax 0.6.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.22"
|
||||
|
@ -1896,13 +2045,35 @@ version = "0.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.24.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
|
||||
dependencies = [
|
||||
"strum_macros 0.24.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125"
|
||||
dependencies = [
|
||||
"strum_macros",
|
||||
"strum_macros 0.25.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.24.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -18,3 +18,5 @@ chrono = { version = "0.4.31", features = ["serde"] }
|
|||
envy = "0.4.2"
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
dotenvy = "0.15.7"
|
||||
rand = "0.8.5"
|
||||
phonenumber = "0.3.3"
|
||||
|
|
111
src/main.rs
111
src/main.rs
|
@ -1,9 +1,30 @@
|
|||
use url::Url;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use url::Url;
|
||||
use chrono::prelude::{NaiveDate, DateTime, Utc};
|
||||
use strum::{Display };
|
||||
use strum::Display;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::collections::HashSet;
|
||||
use rand::{thread_rng, Rng};
|
||||
use phonenumber;
|
||||
|
||||
/// ID
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Id(pub u64);
|
||||
impl Id {
|
||||
pub fn to_string(&self) -> String {
|
||||
format!("{:x}", self.0)
|
||||
}
|
||||
}
|
||||
impl Into<String> for Id {
|
||||
fn into(self) -> String {
|
||||
format!("{:x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_id() -> Id {
|
||||
Id(thread_rng().gen())
|
||||
}
|
||||
|
||||
|
||||
/// permanent config to store long-term config
|
||||
/// used to ingest env settings
|
||||
|
@ -321,7 +342,7 @@ struct Organization {
|
|||
slug: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
enum MembershipMode {
|
||||
#[serde(rename = "Individuel")]
|
||||
Individual,
|
||||
|
@ -410,8 +431,9 @@ fn get_paheko_membership_from_ha_answers() {
|
|||
/// for now we include the custom fields into the paheko user
|
||||
/// we don't have time to implement user settings to change the custom fields mapping
|
||||
/// for now, manual mapping
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
struct PahekoUser {
|
||||
id: Id,
|
||||
first_name: String,
|
||||
last_name: String,
|
||||
email: String,
|
||||
|
@ -425,12 +447,12 @@ struct PahekoUser {
|
|||
birthday: Option<NaiveDate> // we will need to validate some data before
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
struct PahekoMembership {
|
||||
author: PahekoUser,
|
||||
linked_users: Vec<PahekoUser>,
|
||||
id: Id,
|
||||
users: Vec<Id>,
|
||||
campaign: String,
|
||||
mode: String,
|
||||
mode: MembershipMode,
|
||||
inception_datum: DateTime<Utc>
|
||||
}
|
||||
|
||||
|
@ -484,6 +506,21 @@ fn read_custom_field(form_answer: &FormAnswer, custom_field: HelloAssoCustomFiel
|
|||
.and_then(|cf| Some(cf.answer.clone()))
|
||||
}
|
||||
|
||||
fn parse_normalize_phone(phone_number_opt: Option<String>) -> Option<String> {
|
||||
let number_raw = phone_number_opt?;
|
||||
|
||||
let parsed = match phonenumber::parse(Some(phonenumber::country::Id::FR), number_raw) {
|
||||
Ok(r) => {
|
||||
r
|
||||
},
|
||||
Err(_e) => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(parsed.to_string())
|
||||
}
|
||||
|
||||
async fn launch_adapter() -> Result<()> {
|
||||
dotenvy::dotenv()?;
|
||||
|
||||
|
@ -509,9 +546,13 @@ async fn launch_adapter() -> Result<()> {
|
|||
// dbg!(&answers);
|
||||
println!("Got {} answers to the membership form. Processing...", &answers.len());
|
||||
|
||||
// first, request the current list of membership in paheko that were created with helloasso
|
||||
// get the list of payments associated
|
||||
|
||||
// first step: output a list of PahekoUser with PahekoMembership
|
||||
let pk_memberships: Vec<PahekoMembership> = vec![];
|
||||
let mut pk_users: Vec<PahekoUser> = vec![];
|
||||
let mut pk_memberships: Vec<PahekoMembership> = vec![];
|
||||
|
||||
let mut count: u64 = 0;
|
||||
let mut names: HashSet<String> = HashSet::new();
|
||||
|
@ -523,25 +564,65 @@ async fn launch_adapter() -> Result<()> {
|
|||
names.insert(custom_field.name.clone());
|
||||
count += 1;
|
||||
}
|
||||
pk_users.push(PahekoUser {
|
||||
let paheko_user = PahekoUser {
|
||||
id: generate_id(),
|
||||
first_name: answer.user.first_name.clone(),
|
||||
last_name: answer.user.last_name.clone(),
|
||||
email: answer.user.email.clone(),
|
||||
phone: read_custom_field(&answer, HelloAssoCustomFieldType::Phone),
|
||||
phone: parse_normalize_phone(read_custom_field(&answer, HelloAssoCustomFieldType::Phone)),
|
||||
skills: read_custom_field(&answer, HelloAssoCustomFieldType::Skills),
|
||||
address: read_custom_field(&answer, HelloAssoCustomFieldType::Address).expect("to have address"),
|
||||
postal_code: read_custom_field(&answer, HelloAssoCustomFieldType::PostalCode).expect("to have postal code"),
|
||||
city: read_custom_field(&answer, HelloAssoCustomFieldType::City).expect("to have city"),
|
||||
job: read_custom_field(&answer, HelloAssoCustomFieldType::Job),
|
||||
birthday: None
|
||||
});
|
||||
};
|
||||
let mut pk_membership = PahekoMembership {
|
||||
id: generate_id(),
|
||||
campaign: "".to_string(),
|
||||
inception_datum: Utc::now(),
|
||||
mode: answer.mode.clone(),
|
||||
users: vec![paheko_user.id.clone()]
|
||||
};
|
||||
dbg!(&pk_membership.users);
|
||||
// then create optional linked user
|
||||
|
||||
if answer.mode == MembershipMode::Couple {
|
||||
let mut second_pk_user = paheko_user.clone();
|
||||
second_pk_user.id = generate_id();
|
||||
|
||||
match read_custom_field(&answer, HelloAssoCustomFieldType::LinkedUserFirstName) {
|
||||
Some(name) => {
|
||||
second_pk_user.first_name = name
|
||||
},
|
||||
None => {
|
||||
second_pk_user.first_name = "Conjoint".to_string();
|
||||
eprintln!("Got a user with Couple mode but no additional name given!")
|
||||
}
|
||||
}
|
||||
|
||||
pk_membership.users.push(second_pk_user.id.clone());
|
||||
pk_users.push(second_pk_user);
|
||||
}
|
||||
pk_users.push(paheko_user);
|
||||
pk_memberships.push(pk_membership);
|
||||
}
|
||||
dbg!(pk_users);
|
||||
dbg!(names);
|
||||
dbg!(count);
|
||||
dbg!(&pk_users);
|
||||
dbg!(&pk_memberships);
|
||||
dbg!(&pk_users.len());
|
||||
dbg!(&pk_memberships.len());
|
||||
|
||||
|
||||
// println!("{:?}", &pk_users.iter().map(|user| format!("{:?}", user.email)).collect::<Vec<String>>());
|
||||
|
||||
for u in pk_users {
|
||||
println!("{} {}", u.email, u.phone.unwrap_or("".to_string()));
|
||||
}
|
||||
|
||||
|
||||
// then, request the current list of users
|
||||
// match with the email address
|
||||
// we consider the email address as the id for a helloasso user
|
||||
// then, upload the PahekoMembership
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue