diff --git a/.gitignore b/.gitignore index 1af2b0f..504e98f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ # flakes result -/result \ No newline at end of file +/result + +tmp.* \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cc3d3aa..d1f66b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -628,6 +628,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "csv" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626ae34994d3d8d668f4269922248239db4ae42d538b14c398b74a52208e8086" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + [[package]] name = "ctor" version = "0.1.26" @@ -1962,6 +1983,7 @@ version = "0.1.0" dependencies = [ "async-std", "chrono", + "csv", "dotenv", "ldap3", "rand 0.8.5", diff --git a/Cargo.toml b/Cargo.toml index 8e8334b..dc8fd86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,6 @@ rand = "0.8.5" # fancy time stuff chrono = "0.4.26" + +# handlign teh csv export from wolves +csv = "1.2" diff --git a/src/bin/update_groups.rs b/src/bin/update_groups.rs index d103418..c81962f 100644 --- a/src/bin/update_groups.rs +++ b/src/bin/update_groups.rs @@ -1,7 +1,10 @@ use dotenv::dotenv; -use ldap3::{LdapConn, Mod}; +use ldap3::{LdapConn, Mod, Scope, SearchEntry}; use skynet_ldap_backend::{get_config, Config}; -use std::env; +use std::{env, io}; +use std::collections::{HashMap, HashSet}; +use std::error::Error; +use csv; #[async_std::main] async fn main() -> tide::Result<()> { @@ -27,6 +30,9 @@ async fn update_users(config: &Config) -> tide::Result<()> { } } + for user in from_csv(config).await.unwrap_or_default() { + users_tmp.push(user); + } /* pull in data from wolves (csv or api (hopefully api) pull entire ldap data @@ -125,3 +131,103 @@ async fn update_group(config: &Config, group: &str, users: &[&str], replace: boo Ok(()) } + +async fn ldap_get_accounts(config: &Config) -> Result<(HashMap, HashMap), Box>{ + + // connect to ldap + let mut ldap = LdapConn::new(&config.ldap_host)?; + ldap.simple_bind(&config.ldap_admin, &config.ldap_admin_pw)?.success()?; + + let mut uid_idstudent: HashMap = HashMap::new(); + let mut uid_email: HashMap = HashMap::new(); + + let (rs, _res) = ldap.search( + "ou=users,dc=skynet,dc=ie", + Scope::OneLevel, + "(objectClass=*)", + vec!["uid", "mail", "skID", "skSecure"] + ) + .unwrap() + .success() + .unwrap(); + + for entry in rs { + let tmp = SearchEntry::construct(entry); + + // skSecure is a standin for teh password, only 1 if the password is SSHA512 + if !tmp.attrs.contains_key("skSecure"){ + continue; + } + if tmp.attrs["skSecure"].is_empty() { + continue; + } + + // make sure there is an id; + let uid = if !tmp.attrs["uid"].is_empty() { + tmp.attrs["uid"][0].clone() + }else { + continue; + }; + + if !tmp.attrs["skID"].is_empty() { + let skid = tmp.attrs["skID"][0].clone(); + if &skid != "00000000" { + uid_idstudent.insert(skid, uid.clone()); + } + } + + if !tmp.attrs["mail"].is_empty() { + let mail = tmp.attrs["mail"][0].clone(); + if &mail != "nomail@skynet.ie" { + uid_email.insert(mail, uid.clone()); + } + } + } + ldap.unbind()?; + + Ok((uid_idstudent, uid_email)) +} + +async fn from_csv(config: &Config) -> Result, Box>{ + let mut uids = HashSet::new(); + + let (uid_idstudent, uid_email) = ldap_get_accounts(config).await?; + let records = read_csv()?; + + for record in records { + if let Some(uid) = uid_email.get(&record.email) { + uids.insert(uid.clone()); + } + if let Some(uid) = uid_idstudent.get(&record.id_student) { + uids.insert(uid.clone()); + } + } + + Ok(uids) +} + + +#[derive(Debug, serde::Deserialize)] +struct Record { + #[serde(rename = "MemID")] + id_wolves: String, + #[serde(rename = "Student Num")] + id_student: String, + #[serde(rename = "Contact Email")] + email: String, +} + +fn read_csv() -> Result, Box> { + let mut records: Vec = vec![]; + + if let Ok(mut rdr) = csv::Reader::from_path("tmp.csv") { + for result in rdr.deserialize() { + // Notice that we need to provide a type hint for automatic + // deserialization. + let record: Record = result?; + records.push(record); + } + } + + Ok(records) +} \ No newline at end of file