feat: implement CSV export of scholarships
This commit is contained in:
1 parent
be54aa8fd2
commit
c98621aefa
6 files changed
+309
-122
No files matched your search
@@ -0,0 +1,237 @@
|
||||
#[cfg(feature = "ssr")]
|
||||
mod imports {
|
||||
pub use super::super::{COMPARISONS_TABLE, PROVIDER_CONTACT_TABLE, SCHOLARSHIPS_TABLE};
|
||||
pub use crate::common::ValueType;
|
||||
pub use crate::utils::server::create_dynamo_client;
|
||||
pub use aws_sdk_dynamodb::Client;
|
||||
pub use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
||||
pub use indexmap::IndexMap;
|
||||
pub use std::collections::HashMap;
|
||||
}
|
||||
|
||||
use crate::common::ExpandableInfo;
|
||||
use leptos::prelude::*;
|
||||
|
||||
#[server]
|
||||
pub async fn get_scholarship_csv() -> Result<Vec<u8>, ServerFnError> {
|
||||
use imports::*;
|
||||
use leptos::logging::debug_log;
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct ResolvedScholarshipInfo {
|
||||
contact_email: String,
|
||||
first_name: String,
|
||||
last_name: String,
|
||||
scholarship_name: String,
|
||||
sports_requirements: String,
|
||||
gpa_requirements: String,
|
||||
major_requirements: String,
|
||||
additional_requirements: String,
|
||||
community_requirements: String,
|
||||
residency_requirements: String,
|
||||
}
|
||||
|
||||
// Get the scholarships and comparisons
|
||||
let client = create_dynamo_client().await;
|
||||
|
||||
let scan_table = async |client: &Client, table_name| {
|
||||
client
|
||||
.scan()
|
||||
.table_name(table_name)
|
||||
.send()
|
||||
.await
|
||||
.map(|output| output.items)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
serde_dynamo::from_item(item).unwrap_or(ExpandableInfo::new("".to_string()))
|
||||
// item.iter()
|
||||
// .map(|(k, v)| (k.to_owned(), ValueType::from(v)))
|
||||
// .collect::<HashMap<String, ValueType>>()
|
||||
})
|
||||
.collect::<Vec<ExpandableInfo>>()
|
||||
};
|
||||
|
||||
let scan_table_hash_map = async |client: &Client, table_name| {
|
||||
client
|
||||
.scan()
|
||||
.table_name(table_name)
|
||||
.send()
|
||||
.await
|
||||
.map(|output| output.items)
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|item| {
|
||||
// serde_dynamo::from_item(item).unwrap_or(ExpandableInfo::new("".to_string()))
|
||||
item.iter()
|
||||
.map(|(k, v)| (k.to_owned(), ValueType::from(v)))
|
||||
.collect::<HashMap<String, ValueType>>()
|
||||
})
|
||||
.collect::<Vec<HashMap<String, ValueType>>>()
|
||||
};
|
||||
|
||||
let master_scholarships = scan_table(&client, SCHOLARSHIPS_TABLE).await;
|
||||
let master_contacts = scan_table_hash_map(&client, PROVIDER_CONTACT_TABLE).await;
|
||||
let master_relations = scan_table_hash_map(&client, COMPARISONS_TABLE).await;
|
||||
|
||||
// We now want to map the relations to the scholarships, as well as the contacts.
|
||||
// This should take the information from the current scholarship, then relate the IDs of the
|
||||
// requirements in the scholarship to the IDs of the relations in the master list.
|
||||
let resolved_scholarships = master_scholarships
|
||||
.into_iter()
|
||||
.map(|scholarship| {
|
||||
// debug_log!("Scholarship: {:?}", scholarship);
|
||||
// We want the requirements IDs and the provider ID.
|
||||
let requirements_map = scholarship
|
||||
.data
|
||||
.get("requirements")
|
||||
.unwrap_or(&ValueType::Map(None))
|
||||
.as_map()
|
||||
.ok()
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
|
||||
let provider_id = scholarship
|
||||
.data
|
||||
.get("provider_id")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
// Search for the provider ID in the master list.
|
||||
let contact_info = master_contacts
|
||||
.iter()
|
||||
.find(|contact| {
|
||||
let subject = contact
|
||||
.get("subject")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
debug_log!("Comparing {:?} and {:?}", subject, provider_id);
|
||||
|
||||
subject == provider_id
|
||||
})
|
||||
.cloned()
|
||||
.unwrap_or_default();
|
||||
|
||||
// Resolve the requirements - this should resolve as another category-separated map,
|
||||
// but with requirement display text instead of IDs.
|
||||
let resolved_requirements = requirements_map
|
||||
.iter()
|
||||
.map(|(category, selected_val)| {
|
||||
let selected_list = selected_val.as_list().ok().flatten().unwrap_or_default();
|
||||
|
||||
let resolved_names = selected_list
|
||||
.into_iter()
|
||||
.map(|id_val| {
|
||||
let id = id_val.as_string().ok().flatten().unwrap_or_default();
|
||||
|
||||
let resolved_relation = master_relations
|
||||
.iter()
|
||||
.find(|item| {
|
||||
let comp_id = item
|
||||
.get("id")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
comp_id == id
|
||||
})
|
||||
.cloned()
|
||||
.map(|v| {
|
||||
v.get("display_text").map(|text_opt| {
|
||||
text_opt.as_string().ok().flatten().unwrap_or_default()
|
||||
})
|
||||
})
|
||||
.flatten()
|
||||
.unwrap_or_default();
|
||||
|
||||
resolved_relation
|
||||
})
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
(category.clone(), resolved_names)
|
||||
})
|
||||
.collect::<IndexMap<String, Vec<String>>>();
|
||||
debug_log!("Resolved requirements: {:?}", resolved_requirements);
|
||||
|
||||
let contact_email = contact_info
|
||||
.get("contact_email")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
let first_name = contact_info
|
||||
.get("first_name")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
let last_name = contact_info
|
||||
.get("last_name")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
let scholarship_name = scholarship
|
||||
.data
|
||||
.get("name")
|
||||
.map(|v| v.as_string().ok().flatten().unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
debug_log!(
|
||||
"{:?}, {:?}, {:?}, {:?}",
|
||||
scholarship_name,
|
||||
contact_email,
|
||||
first_name,
|
||||
last_name
|
||||
);
|
||||
|
||||
// We want to create some structure that's got the correct information. Specifically,
|
||||
// we only need the provider contact info, the scholarship's name, and the requirements
|
||||
// that they chose in plain text.
|
||||
ResolvedScholarshipInfo {
|
||||
first_name,
|
||||
last_name,
|
||||
contact_email,
|
||||
scholarship_name,
|
||||
sports_requirements: resolved_requirements
|
||||
.get("sports_participation")
|
||||
.map(|list| list.join("; "))
|
||||
.unwrap_or_default(),
|
||||
gpa_requirements: resolved_requirements
|
||||
.get("gpa")
|
||||
.map(|list| list.join("; "))
|
||||
.unwrap_or_default(),
|
||||
major_requirements: resolved_requirements
|
||||
.get("major")
|
||||
.map(|list| list.join("; "))
|
||||
.unwrap_or_default(),
|
||||
additional_requirements: resolved_requirements
|
||||
.get("misc")
|
||||
.map(|list| list.join("; "))
|
||||
.unwrap_or_default(),
|
||||
community_requirements: resolved_requirements
|
||||
.get("community_service")
|
||||
.map(|list| list.join("; "))
|
||||
.unwrap_or_default(),
|
||||
residency_requirements: resolved_requirements
|
||||
.get("residency")
|
||||
.map(|list| list.join("; "))
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<ResolvedScholarshipInfo>>();
|
||||
|
||||
// Now that we have a series of scholarships, we need to serialize them into CSV and send the
|
||||
// file to the client.
|
||||
let mut writer = csv::Writer::from_writer(Vec::new());
|
||||
resolved_scholarships.iter().for_each(|scholarship| {
|
||||
_ = writer.serialize(scholarship);
|
||||
});
|
||||
writer.flush()?;
|
||||
|
||||
let result = writer.into_inner()?;
|
||||
debug_log!("{:?}", String::from_utf8(result.clone()));
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
mod comparisons;
|
||||
mod scholarships;
|
||||
mod dates;
|
||||
mod admin;
|
||||
mod comparisons;
|
||||
mod dates;
|
||||
pub mod exports;
|
||||
mod providers;
|
||||
mod scholarships;
|
||||
pub mod students;
|
||||
|
||||
pub use comparisons::*;
|
||||
pub use scholarships::*;
|
||||
pub use dates::*;
|
||||
pub use admin::*;
|
||||
pub use comparisons::*;
|
||||
pub use dates::*;
|
||||
pub use providers::*;
|
||||
pub use scholarships::*;
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
pub static COMPARISONS_TABLE: &str = "leptos-comparisons";
|
||||
|
||||
Reference in new issue
Block a user