Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9d5b25436 | ||
|
|
891e324186 | ||
|
|
b502c2f96d | ||
|
|
681da8c326 | ||
|
|
628b607074 | ||
|
|
97be249826 | ||
|
|
e1bd472a36 | ||
|
|
dd19631e33 | ||
|
|
a0b206a554 | ||
|
|
e9b0452d38 | ||
|
|
448e8bbb38 | ||
|
|
ae7a17ad92 | ||
|
|
750059e9ad | ||
|
|
5a371ae574 | ||
|
|
d7f44463c6 | ||
|
|
5872002538 | ||
|
|
957fc0c5eb |
No files matched your search
+7
-7
@@ -1,11 +1,11 @@
|
|||||||
use crate::components::ToastList;
|
use crate::components::ToastList;
|
||||||
use crate::components::login::ProviderLoginContext;
|
use crate::components::login::ProviderLoginContext;
|
||||||
|
use crate::pages::student;
|
||||||
use crate::pages::{
|
use crate::pages::{
|
||||||
AdminHomePage, AdminProviderPage, AdminScholarshipPage, AdminShell, AdminUtilsPage,
|
AdminHomePage, AdminProviderPage, AdminScholarshipPage, AdminShell, AdminUtilsPage,
|
||||||
ApplicantsPageFallback, AuthCallbackPage, LoanerBorrowForm, LoanerFallback, LoanerReturnForm,
|
ApplicantsPageFallback, AuthCallbackPage, LoanerBorrowForm, LoanerFallback, LoanerReturnForm,
|
||||||
LoanerShell, ProviderContactPage, ProviderPortal,
|
LoanerShell, ProviderContactPage, ProviderPortal, ScholarshipInfoPage,
|
||||||
};
|
};
|
||||||
use crate::pages::{FormClosedPage, student};
|
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
|
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
|
||||||
use leptos_oidc::AuthSignal;
|
use leptos_oidc::AuthSignal;
|
||||||
@@ -89,11 +89,11 @@ fn ProviderRoutes() -> impl MatchNestedRoutes + Clone {
|
|||||||
<Route path=path!("/applicants") view=ApplicantsPageFallback />
|
<Route path=path!("/applicants") view=ApplicantsPageFallback />
|
||||||
<Route path=path!("/callback") view=AuthCallbackPage />
|
<Route path=path!("/callback") view=AuthCallbackPage />
|
||||||
<Route path=path!("/profile") view=ProviderContactPage />
|
<Route path=path!("/profile") view=ProviderContactPage />
|
||||||
<Route path=path!("/scholarships") view=FormClosedPage />
|
// <Route path=path!("/scholarships") view=FormClosedPage />
|
||||||
// <ParentRoute path=path!("/scholarships") view=FormClosedPage>
|
<ParentRoute path=path!("/scholarships") view=ScholarshipInfoPage>
|
||||||
// <Route path=path!(":id") view=FormClosedPage />
|
<Route path=path!(":id") view=ScholarshipInfoPage />
|
||||||
// <Route path=path!("") view=FormClosedPage />
|
<Route path=path!("") view=ScholarshipInfoPage />
|
||||||
// </ParentRoute>
|
</ParentRoute>
|
||||||
</ParentRoute>
|
</ParentRoute>
|
||||||
}
|
}
|
||||||
.into_inner()
|
.into_inner()
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ use crate::common::{
|
|||||||
ComparisonData, ComparisonType, MapListComparison, NumberComparison, NumberListComparison,
|
ComparisonData, ComparisonType, MapListComparison, NumberComparison, NumberListComparison,
|
||||||
TextComparison, TextListComparison, ValueType,
|
TextComparison, TextListComparison, ValueType,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
|
||||||
use leptos::prelude::ServerFnError;
|
use leptos::prelude::ServerFnError;
|
||||||
use leptos::server;
|
use leptos::server;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// Helper function to create all sports comparisons. Only used to create initial
|
/// Helper function to create all sports comparisons. Only used to create initial
|
||||||
/// comparison data, and should be removed upon completion of a comparison editor page.
|
/// comparison data, and should be removed upon completion of a comparison editor page.
|
||||||
@@ -250,14 +249,18 @@ fn create_major_comparisons() -> Vec<ComparisonData> {
|
|||||||
|
|
||||||
let ids = display_texts
|
let ids = display_texts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|text|
|
.map(|text| {
|
||||||
format!("{}_{}", "major", text.to_lowercase().replace(" ", "_").replace("/", "_"))
|
format!(
|
||||||
)
|
"{}_{}",
|
||||||
|
"major",
|
||||||
|
text.to_lowercase().replace(" ", "_").replace("/", "_")
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
ids.iter().zip(display_texts).map(|(id, display_text)| {
|
ids.iter()
|
||||||
create_major_comparison(id, display_text)
|
.zip(display_texts)
|
||||||
})
|
.map(|(id, display_text)| create_major_comparison(id, display_text))
|
||||||
.collect::<Vec<ComparisonData>>()
|
.collect::<Vec<ComparisonData>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,13 +283,11 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
"Academic Information",
|
"Academic Information",
|
||||||
"Math SAT Score > 650",
|
"Math SAT Score > 650",
|
||||||
);
|
);
|
||||||
|
|
||||||
let service_hours_20 = ComparisonData::new(
|
let service_hours_20 = ComparisonData::new(
|
||||||
"service_hours_20",
|
"service_hours_20",
|
||||||
"service_hours",
|
"service_hours",
|
||||||
ComparisonType::Number(
|
ComparisonType::Number(NumberComparison::GreaterThanOrEqual),
|
||||||
NumberComparison::GreaterThanOrEqual
|
|
||||||
),
|
|
||||||
ValueType::Number(Some(20.to_string())),
|
ValueType::Number(Some(20.to_string())),
|
||||||
"Community Service",
|
"Community Service",
|
||||||
"20+ service hours",
|
"20+ service hours",
|
||||||
@@ -295,9 +296,7 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
let service_hours_25 = ComparisonData::new(
|
let service_hours_25 = ComparisonData::new(
|
||||||
"service_hours_25",
|
"service_hours_25",
|
||||||
"service_hours",
|
"service_hours",
|
||||||
ComparisonType::Number(
|
ComparisonType::Number(NumberComparison::GreaterThanOrEqual),
|
||||||
NumberComparison::GreaterThanOrEqual
|
|
||||||
),
|
|
||||||
ValueType::Number(Some(25.to_string())),
|
ValueType::Number(Some(25.to_string())),
|
||||||
"Community Service",
|
"Community Service",
|
||||||
"25+ service hours",
|
"25+ service hours",
|
||||||
@@ -306,9 +305,7 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
let service_hours_30 = ComparisonData::new(
|
let service_hours_30 = ComparisonData::new(
|
||||||
"service_hours_30",
|
"service_hours_30",
|
||||||
"service_hours",
|
"service_hours",
|
||||||
ComparisonType::Number(
|
ComparisonType::Number(NumberComparison::GreaterThanOrEqual),
|
||||||
NumberComparison::GreaterThanOrEqual
|
|
||||||
),
|
|
||||||
ValueType::Number(Some(30.to_string())),
|
ValueType::Number(Some(30.to_string())),
|
||||||
"Community Service",
|
"Community Service",
|
||||||
"30+ service hours",
|
"30+ service hours",
|
||||||
@@ -334,7 +331,7 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
|
|
||||||
let attended_bas = ComparisonData::new(
|
let attended_bas = ComparisonData::new(
|
||||||
"attended_bas",
|
"attended_bas",
|
||||||
"attended_bas",
|
"attend_bas",
|
||||||
ComparisonType::Text(TextComparison::Matches),
|
ComparisonType::Text(TextComparison::Matches),
|
||||||
ValueType::String(Some("Yes".to_string())),
|
ValueType::String(Some("Yes".to_string())),
|
||||||
"Additional Eligibility Factors",
|
"Additional Eligibility Factors",
|
||||||
@@ -365,7 +362,7 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
ComparisonType::Text(TextComparison::Matches),
|
ComparisonType::Text(TextComparison::Matches),
|
||||||
ValueType::String(Some("Yes".to_string())),
|
ValueType::String(Some("Yes".to_string())),
|
||||||
"Additional Eligibility Factors",
|
"Additional Eligibility Factors",
|
||||||
"Participated in Pomperaug Youth Baseball"
|
"Participated in Pomperaug Youth Baseball",
|
||||||
);
|
);
|
||||||
|
|
||||||
let aquatic_club = ComparisonData::new(
|
let aquatic_club = ComparisonData::new(
|
||||||
@@ -374,25 +371,25 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
ComparisonType::Text(TextComparison::Matches),
|
ComparisonType::Text(TextComparison::Matches),
|
||||||
ValueType::String(Some("Yes".to_string())),
|
ValueType::String(Some("Yes".to_string())),
|
||||||
"Additional Eligibility Factors",
|
"Additional Eligibility Factors",
|
||||||
"Participated in Panthers Aquatic Club"
|
"Participated in Panthers Aquatic Club",
|
||||||
);
|
);
|
||||||
|
|
||||||
let pea_member = ComparisonData::new(
|
let pea_member = ComparisonData::new(
|
||||||
"pea_member",
|
"pea_member",
|
||||||
"pea_member",
|
"pea_member",
|
||||||
ComparisonType::Text(TextComparison::Matches),
|
ComparisonType::Text(TextComparison::Matches),
|
||||||
ValueType::String(Some("Yes".to_string())),
|
ValueType::String(Some("Yes".to_string())),
|
||||||
"Additional Eligibility Factors",
|
"Additional Eligibility Factors",
|
||||||
"Has a Parent in the PEA"
|
"Has a Parent in the PEA",
|
||||||
);
|
);
|
||||||
|
|
||||||
let music_program = ComparisonData::new(
|
let music_program = ComparisonData::new(
|
||||||
"music_program",
|
"music_program",
|
||||||
"music_program",
|
"music_program",
|
||||||
ComparisonType::Text(TextComparison::Matches),
|
ComparisonType::Text(TextComparison::Matches),
|
||||||
ValueType::String(Some("Yes".to_string())),
|
ValueType::String(Some("Yes".to_string())),
|
||||||
"Sports Participation",
|
"Sports Participation",
|
||||||
"PHS Music Program"
|
"PHS Music Program",
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut sports_comps = create_sports_comparisons();
|
let mut sports_comps = create_sports_comparisons();
|
||||||
@@ -412,7 +409,7 @@ fn make_comp_list() -> Vec<ComparisonData> {
|
|||||||
youth_baseball,
|
youth_baseball,
|
||||||
aquatic_club,
|
aquatic_club,
|
||||||
pea_member,
|
pea_member,
|
||||||
music_program
|
music_program,
|
||||||
];
|
];
|
||||||
|
|
||||||
comp_list.append(&mut sports_comps);
|
comp_list.append(&mut sports_comps);
|
||||||
@@ -438,6 +435,7 @@ pub async fn create_test_comparisons() -> Result<(), ServerFnError> {
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("An unknown error occurred");
|
||||||
|
leptos::logging::error!("{}", msg);
|
||||||
return Err(ServerFnError::new(msg));
|
return Err(ServerFnError::new(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -453,15 +451,9 @@ pub async fn get_comparison_info() -> Result<Vec<ComparisonData>, ServerFnError>
|
|||||||
|
|
||||||
// Query the database for all comparisons. The client is only going to use the
|
// Query the database for all comparisons. The client is only going to use the
|
||||||
// id and display text, but we'll return the whole thing.
|
// id and display text, but we'll return the whole thing.
|
||||||
match client
|
match client.scan().table_name(COMPARISONS_TABLE).send().await {
|
||||||
.scan()
|
|
||||||
.table_name(COMPARISONS_TABLE)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
if let Some(items) = output.items {
|
if let Some(items) = output.items {
|
||||||
log!("Found comparisons from API: {:?}", items);
|
|
||||||
Ok(serde_dynamo::from_items(items)?)
|
Ok(serde_dynamo::from_items(items)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
@@ -469,22 +461,19 @@ pub async fn get_comparison_info() -> Result<Vec<ComparisonData>, ServerFnError>
|
|||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("An unknown error occurred");
|
||||||
|
leptos::logging::error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn get_comparisons_categorized() -> Result<HashMap<String, Vec<ComparisonData>>, ServerFnError> {
|
pub async fn get_comparisons_categorized()
|
||||||
|
-> Result<HashMap<String, Vec<ComparisonData>>, ServerFnError> {
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
log!("Getting all comparisons from the database, by category.");
|
log!("Getting all comparisons from the database, by category.");
|
||||||
|
|
||||||
match client
|
match client.scan().table_name(COMPARISONS_TABLE).send().await {
|
||||||
.scan()
|
|
||||||
.table_name(COMPARISONS_TABLE)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
if let Some(items) = output.items {
|
if let Some(items) = output.items {
|
||||||
log!("Found comparisons, categorizing.");
|
log!("Found comparisons, categorizing.");
|
||||||
@@ -492,23 +481,27 @@ pub async fn get_comparisons_categorized() -> Result<HashMap<String, Vec<Compari
|
|||||||
let items: Vec<ComparisonData> = serde_dynamo::from_items(items)?;
|
let items: Vec<ComparisonData> = serde_dynamo::from_items(items)?;
|
||||||
|
|
||||||
let categorized = items.iter().fold(
|
let categorized = items.iter().fold(
|
||||||
HashMap::<String, Vec<ComparisonData>>::new(), |mut map, comp| {
|
HashMap::<String, Vec<ComparisonData>>::new(),
|
||||||
// Load each comparison into a map, then return that map.
|
|mut map, comp| {
|
||||||
|
// Load each comparison into a map, then return that map.
|
||||||
map.entry(comp.category.clone())
|
map.entry(comp.category.clone())
|
||||||
.and_modify(|vec| vec.push(comp.clone()))
|
.and_modify(|vec| vec.push(comp.clone()))
|
||||||
.or_insert(vec![comp.clone()]);
|
.or_insert(vec![comp.clone()]);
|
||||||
|
|
||||||
map
|
map
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(categorized)
|
Ok(categorized)
|
||||||
} else {
|
} else {
|
||||||
Err(ServerFnError::new("Couldn't find any comparisons."))
|
let msg = "Couldn't find any comparisons.";
|
||||||
|
leptos::logging::error!("{}", msg);
|
||||||
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("An unknown error occurred");
|
||||||
|
leptos::logging::error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-32
@@ -1,61 +1,60 @@
|
|||||||
use std::collections::HashMap;
|
|
||||||
use leptos::logging::log;
|
|
||||||
use leptos::prelude::*;
|
|
||||||
use crate::common::DateInfo;
|
use crate::common::DateInfo;
|
||||||
|
use leptos::logging::{error, log};
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
use super::DATES_TABLE;
|
use super::DATES_TABLE;
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
|
||||||
use aws_sdk_dynamodb::{
|
|
||||||
types::{WriteRequest, PutRequest},
|
|
||||||
Client as DynamoClient
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
use crate::utils::server::create_dynamo_client;
|
use crate::utils::server::create_dynamo_client;
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
use std::sync::Arc;
|
use aws_sdk_dynamodb::{
|
||||||
|
Client as DynamoClient,
|
||||||
|
error::ProvideErrorMetadata,
|
||||||
|
types::{PutRequest, WriteRequest},
|
||||||
|
};
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn create_dates(dates: Vec<DateInfo>) -> Result<(), ServerFnError> {
|
pub async fn create_dates(dates: Vec<DateInfo>) -> Result<(), ServerFnError> {
|
||||||
// Serialize and put dates into the database.
|
// Serialize and put dates into the database.
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
log!("Creating dates: {:?}", dates);
|
log!("Creating dates: {:?}", dates);
|
||||||
|
|
||||||
let requests = dates
|
let requests = dates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|date| {
|
.filter_map(|date| {
|
||||||
let item = serde_dynamo::to_item(&date)
|
let item = serde_dynamo::to_item(&date).unwrap_or_default();
|
||||||
.unwrap_or_default();
|
|
||||||
|
let put_request = PutRequest::builder().set_item(Some(item)).build().ok()?;
|
||||||
let put_request = PutRequest::builder()
|
|
||||||
.set_item(Some(item))
|
Some(WriteRequest::builder().put_request(put_request).build())
|
||||||
.build()
|
|
||||||
.expect("Couldn't build request, item is not present");
|
|
||||||
|
|
||||||
WriteRequest::builder().put_request(put_request).build()
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<WriteRequest>>();
|
.collect::<Vec<WriteRequest>>();
|
||||||
|
|
||||||
let mut request_map = HashMap::new();
|
let mut request_map = HashMap::new();
|
||||||
request_map.insert(DATES_TABLE.to_string(), requests);
|
request_map.insert(DATES_TABLE.to_string(), requests);
|
||||||
|
|
||||||
client
|
client
|
||||||
.batch_write_item()
|
.batch_write_item()
|
||||||
.set_request_items(Some(request_map))
|
.set_request_items(Some(request_map))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(ServerFnError::from)
|
.map_err(|err| {
|
||||||
|
let msg = err.message().unwrap_or("Unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn get_important_dates() -> Result<Vec<DateInfo>, ServerFnError> {
|
pub async fn get_important_dates() -> Result<Vec<DateInfo>, ServerFnError> {
|
||||||
|
log!("Getting important dates list");
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
client
|
client
|
||||||
.scan()
|
.scan()
|
||||||
.table_name(DATES_TABLE)
|
.table_name(DATES_TABLE)
|
||||||
@@ -65,14 +64,15 @@ pub async fn get_important_dates() -> Result<Vec<DateInfo>, ServerFnError> {
|
|||||||
if let Some(items) = output.items {
|
if let Some(items) = output.items {
|
||||||
items
|
items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|item| {
|
.filter_map(|item| serde_dynamo::from_item::<_, DateInfo>(item).ok())
|
||||||
serde_dynamo::from_item::<_, DateInfo>(item)
|
|
||||||
.ok()
|
|
||||||
})
|
|
||||||
.collect::<Vec<DateInfo>>()
|
.collect::<Vec<DateInfo>>()
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.map_err(ServerFnError::from)
|
.map_err(|err| {
|
||||||
|
let msg = err.message().unwrap_or("Unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,6 @@ pub async fn get_scholarship_csv() -> Result<Vec<u8>, ServerFnError> {
|
|||||||
writer.flush()?;
|
writer.flush()?;
|
||||||
|
|
||||||
let result = writer.into_inner()?;
|
let result = writer.into_inner()?;
|
||||||
debug_log!("{:?}", String::from_utf8(result.clone()));
|
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
+53
-18
@@ -1,4 +1,5 @@
|
|||||||
use leptos::logging::debug_log;
|
use leptos::leptos_dom::error;
|
||||||
|
use leptos::logging::debug_log;
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use server_fn::codec::{MultipartData, MultipartFormData};
|
use server_fn::codec::{MultipartData, MultipartFormData};
|
||||||
|
|
||||||
@@ -7,7 +8,11 @@ mod imports {
|
|||||||
pub use super::super::{MAIN_TABLE_NAME, S3_BUCKET_NAME};
|
pub use super::super::{MAIN_TABLE_NAME, S3_BUCKET_NAME};
|
||||||
pub use crate::pages::api::tokens::validate_and_get_token_info;
|
pub use crate::pages::api::tokens::validate_and_get_token_info;
|
||||||
pub use crate::utils::server::create_aws_config;
|
pub use crate::utils::server::create_aws_config;
|
||||||
pub use aws_sdk_dynamodb::types::{AttributeValue, ReturnValue, Select};
|
pub use aws_sdk_dynamodb::{
|
||||||
|
error::ProvideErrorMetadata as _,
|
||||||
|
types::{AttributeValue, ReturnValue, Select},
|
||||||
|
};
|
||||||
|
pub use aws_sdk_s3::error::ProvideErrorMetadata as _;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(input = MultipartFormData)]
|
#[server(input = MultipartFormData)]
|
||||||
@@ -57,6 +62,9 @@ pub async fn upload_file(data: MultipartData) -> Result<String, ServerFnError> {
|
|||||||
if input_name.is_empty() {
|
if input_name.is_empty() {
|
||||||
return Err(ServerFnError::new("Missing input file"));
|
return Err(ServerFnError::new("Missing input file"));
|
||||||
}
|
}
|
||||||
|
if file_bytes.is_empty() {
|
||||||
|
return Err(ServerFnError::new("Missing file contents"));
|
||||||
|
}
|
||||||
|
|
||||||
let user_claims = validate_and_get_token_info(access_token).await?;
|
let user_claims = validate_and_get_token_info(access_token).await?;
|
||||||
let subject = user_claims.subject;
|
let subject = user_claims.subject;
|
||||||
@@ -75,7 +83,14 @@ pub async fn upload_file(data: MultipartData) -> Result<String, ServerFnError> {
|
|||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(|e| ServerFnError::new(format!("Couldn't put file to S3: {}", e.to_string())))?;
|
.map_err(|e| {
|
||||||
|
let msg = format!(
|
||||||
|
"Couldn't put file to S3: {}",
|
||||||
|
e.message().unwrap_or("Unknown error occurred")
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})?;
|
||||||
|
|
||||||
// Besides uploading the file to S3, we also want to store a FILE entry in Dynamo.
|
// Besides uploading the file to S3, we also want to store a FILE entry in Dynamo.
|
||||||
// This will allow the server to quickly return a list of all files that a specific user has
|
// This will allow the server to quickly return a list of all files that a specific user has
|
||||||
@@ -101,11 +116,13 @@ pub async fn upload_file(data: MultipartData) -> Result<String, ServerFnError> {
|
|||||||
.item("file_key".to_string(), AttributeValue::S(key.clone()))
|
.item("file_key".to_string(), AttributeValue::S(key.clone()))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|err| {
|
||||||
ServerFnError::new(format!(
|
let msg = format!(
|
||||||
"Couldn't put file to Dynamo, file rolled back: {}",
|
"Couldn't put file to Dynamo, file rolled back: {}",
|
||||||
e.to_string()
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
))
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
});
|
});
|
||||||
|
|
||||||
// If Dynamo fails, we want to handle the error by rolling back the file. Then, we return a failure.
|
// If Dynamo fails, we want to handle the error by rolling back the file. Then, we return a failure.
|
||||||
@@ -116,11 +133,13 @@ pub async fn upload_file(data: MultipartData) -> Result<String, ServerFnError> {
|
|||||||
.key(&key)
|
.key(&key)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|err| {
|
||||||
ServerFnError::new(format!(
|
let msg = format!(
|
||||||
"Couldn't roll back S3 operation: {}",
|
"Failed to rollback Dynamo entry: {}",
|
||||||
e.to_string()
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
))
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
@@ -167,7 +186,14 @@ pub async fn delete_file(
|
|||||||
.key(key)
|
.key(key)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(ServerFnError::from);
|
.map_err(|err| {
|
||||||
|
let msg = format!(
|
||||||
|
"Failed to put file into S3: {}",
|
||||||
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
});
|
||||||
|
|
||||||
if let Err(err) = s3_result {
|
if let Err(err) = s3_result {
|
||||||
// Add the key back to Dynamo and return an error.
|
// Add the key back to Dynamo and return an error.
|
||||||
@@ -178,10 +204,12 @@ pub async fn delete_file(
|
|||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
ServerFnError::new(format!(
|
let msg = format!(
|
||||||
"Couldn't roll back Dynamo operation: {}",
|
"Failed to rollback Dynamo entry: {}",
|
||||||
err.to_string()
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
))
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
return Err(err);
|
return Err(err);
|
||||||
@@ -230,5 +258,12 @@ pub async fn list_files(
|
|||||||
})
|
})
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
})
|
})
|
||||||
.map_err(|e| ServerFnError::new(format!("Couldn't list files: {}", e.to_string())))
|
.map_err(|err| {
|
||||||
|
let msg = format!(
|
||||||
|
"Failed to get files: {}",
|
||||||
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
+23
-12
@@ -1,8 +1,8 @@
|
|||||||
use leptos::prelude::*;
|
use crate::common::ValueType;
|
||||||
use leptos::logging::debug_log;
|
use leptos::logging::{debug_log, error};
|
||||||
use std::collections::HashMap;
|
use leptos::prelude::*;
|
||||||
use leptos::server_fn::codec::Json;
|
use leptos::server_fn::codec::Json;
|
||||||
use crate::common::ValueType;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
use crate::utils::server::{create_dynamo_client, into_attr_map};
|
use crate::utils::server::{create_dynamo_client, into_attr_map};
|
||||||
@@ -12,8 +12,8 @@ static PROVIDER_CONTACT_TABLE: &str = "leptos-provider-contacts";
|
|||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn get_provider_contact(id: String) -> Result<HashMap<String, ValueType>, ServerFnError> {
|
pub async fn get_provider_contact(id: String) -> Result<HashMap<String, ValueType>, ServerFnError> {
|
||||||
use aws_sdk_dynamodb::types::AttributeValue;
|
|
||||||
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
||||||
|
use aws_sdk_dynamodb::types::AttributeValue;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
@@ -31,29 +31,39 @@ pub async fn get_provider_contact(id: String) -> Result<HashMap<String, ValueTyp
|
|||||||
return Ok(HashMap::new());
|
return Ok(HashMap::new());
|
||||||
};
|
};
|
||||||
|
|
||||||
let map = item.iter().map(|(key, val)| {
|
let map = item
|
||||||
let val_type = ValueType::from(val);
|
.iter()
|
||||||
|
.map(|(key, val)| {
|
||||||
|
let val_type = ValueType::from(val);
|
||||||
|
|
||||||
(key.clone(), val_type)
|
(key.clone(), val_type)
|
||||||
}).collect::<HashMap<String, ValueType>>();
|
})
|
||||||
|
.collect::<HashMap<String, ValueType>>();
|
||||||
|
|
||||||
Ok(map)
|
Ok(map)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred.");
|
let msg = err.message().unwrap_or("An unknown error occurred.");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(input = Json)]
|
#[server(input = Json)]
|
||||||
pub async fn put_provider_contact(id: String, contact_info: HashMap<String, ValueType>) -> Result<(), ServerFnError> {
|
pub async fn put_provider_contact(
|
||||||
|
id: String,
|
||||||
|
contact_info: HashMap<String, ValueType>,
|
||||||
|
) -> Result<(), ServerFnError> {
|
||||||
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
let mut item = into_attr_map(contact_info);
|
let mut item = into_attr_map(contact_info);
|
||||||
item.insert("subject".to_owned(), aws_sdk_dynamodb::types::AttributeValue::S(id));
|
item.insert(
|
||||||
|
"subject".to_owned(),
|
||||||
|
aws_sdk_dynamodb::types::AttributeValue::S(id),
|
||||||
|
);
|
||||||
|
|
||||||
match client
|
match client
|
||||||
.put_item()
|
.put_item()
|
||||||
@@ -65,7 +75,8 @@ pub async fn put_provider_contact(id: String, contact_info: HashMap<String, Valu
|
|||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred.");
|
let msg = err.message().unwrap_or("An unknown error occurred.");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
mod imports {
|
mod imports {
|
||||||
pub use leptos::logging::debug_log;
|
|
||||||
pub use aws_sdk_dynamodb::{
|
|
||||||
types::AttributeValue,
|
|
||||||
error::ProvideErrorMetadata,
|
|
||||||
};
|
|
||||||
pub use leptos::leptos_dom::log;
|
|
||||||
pub use uuid::Uuid;
|
|
||||||
pub use crate::utils::server::{create_dynamo_client};
|
|
||||||
pub use crate::common::ValueType;
|
|
||||||
pub use super::super::SCHOLARSHIPS_TABLE;
|
pub use super::super::SCHOLARSHIPS_TABLE;
|
||||||
|
pub use crate::common::ValueType;
|
||||||
|
pub use crate::utils::server::create_dynamo_client;
|
||||||
|
pub use aws_sdk_dynamodb::{error::ProvideErrorMetadata, types::AttributeValue};
|
||||||
|
pub use leptos::logging::{debug_log, error, log};
|
||||||
|
pub use uuid::Uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::common::ExpandableInfo;
|
use crate::common::ExpandableInfo;
|
||||||
@@ -20,7 +16,7 @@ use leptos::server_fn::codec::Json;
|
|||||||
#[server(GetScholarshipInfo)]
|
#[server(GetScholarshipInfo)]
|
||||||
pub async fn get_scholarship_info(id: String) -> Result<ExpandableInfo, ServerFnError> {
|
pub async fn get_scholarship_info(id: String) -> Result<ExpandableInfo, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
// Perform the operation - we just want to return all data that's contained in this entry,
|
// Perform the operation - we just want to return all data that's contained in this entry,
|
||||||
@@ -39,11 +35,14 @@ pub async fn get_scholarship_info(id: String) -> Result<ExpandableInfo, ServerFn
|
|||||||
Ok(serde_dynamo::from_item(item)?)
|
Ok(serde_dynamo::from_item(item)?)
|
||||||
} else {
|
} else {
|
||||||
log!("Couldn't find scholarship with ID {:?}", id);
|
log!("Couldn't find scholarship with ID {:?}", id);
|
||||||
Err(ServerFnError::new("Couldn't find scholarship with given ID."))
|
Err(ServerFnError::new(
|
||||||
|
"Couldn't find scholarship with given ID.",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("An unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,12 +50,15 @@ pub async fn get_scholarship_info(id: String) -> Result<ExpandableInfo, ServerFn
|
|||||||
|
|
||||||
#[server(CreateScholarshipInfo, input = Json)]
|
#[server(CreateScholarshipInfo, input = Json)]
|
||||||
pub async fn create_scholarship_info(info: ExpandableInfo) -> Result<(), ServerFnError> {
|
pub async fn create_scholarship_info(info: ExpandableInfo) -> Result<(), ServerFnError> {
|
||||||
use imports::*;
|
|
||||||
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
||||||
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
log!("Creating or updating scholarship with ID {:?}", info.subject);
|
log!(
|
||||||
|
"Creating or updating scholarship with ID {:?}",
|
||||||
|
info.subject
|
||||||
|
);
|
||||||
|
|
||||||
match client
|
match client
|
||||||
.put_item()
|
.put_item()
|
||||||
@@ -68,6 +70,7 @@ pub async fn create_scholarship_info(info: ExpandableInfo) -> Result<(), ServerF
|
|||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("An unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,24 +79,20 @@ pub async fn create_scholarship_info(info: ExpandableInfo) -> Result<(), ServerF
|
|||||||
#[server(GetAllScholarshipInfo)]
|
#[server(GetAllScholarshipInfo)]
|
||||||
pub async fn get_all_scholarship_info() -> Result<Vec<ExpandableInfo>, ServerFnError> {
|
pub async fn get_all_scholarship_info() -> Result<Vec<ExpandableInfo>, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
debug_log!("Getting all scholarship info");
|
debug_log!("Getting all scholarship info");
|
||||||
match client
|
match client.scan().table_name(SCHOLARSHIPS_TABLE).send().await {
|
||||||
.scan()
|
|
||||||
.table_name(SCHOLARSHIPS_TABLE)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
if let Some(items) = output.items {
|
if let Some(items) = output.items {
|
||||||
Ok(serde_dynamo::from_items(items)?)
|
Ok(serde_dynamo::from_items(items)?)
|
||||||
} else {
|
} else {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("Unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,17 +100,25 @@ pub async fn get_all_scholarship_info() -> Result<Vec<ExpandableInfo>, ServerFnE
|
|||||||
|
|
||||||
/// Gets all scholarships that are associated with the given scholarship provider's ID.
|
/// Gets all scholarships that are associated with the given scholarship provider's ID.
|
||||||
#[server(GetProviderScholarships)]
|
#[server(GetProviderScholarships)]
|
||||||
pub async fn get_provider_scholarships(provider_id: String) -> Result<Vec<ExpandableInfo>, ServerFnError> {
|
pub async fn get_provider_scholarships(
|
||||||
|
provider_id: String,
|
||||||
|
) -> Result<Vec<ExpandableInfo>, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
debug_log!("Getting provider scholarships for provider with ID {:?}", provider_id);
|
debug_log!(
|
||||||
|
"Getting provider scholarships for provider with ID {:?}",
|
||||||
|
provider_id
|
||||||
|
);
|
||||||
|
|
||||||
match client
|
match client
|
||||||
.scan()
|
.scan()
|
||||||
.table_name(SCHOLARSHIPS_TABLE)
|
.table_name(SCHOLARSHIPS_TABLE)
|
||||||
.expression_attribute_values(":id", serde_dynamo::to_attribute_value(ValueType::String(Some(provider_id)))?)
|
.expression_attribute_values(
|
||||||
|
":id",
|
||||||
|
serde_dynamo::to_attribute_value(ValueType::String(Some(provider_id)))?,
|
||||||
|
)
|
||||||
.filter_expression("provider_id = :id")
|
.filter_expression("provider_id = :id")
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
@@ -124,7 +131,8 @@ pub async fn get_provider_scholarships(provider_id: String) -> Result<Vec<Expand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("Unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,14 +142,20 @@ pub async fn get_provider_scholarships(provider_id: String) -> Result<Vec<Expand
|
|||||||
#[server(RegisterScholarship)]
|
#[server(RegisterScholarship)]
|
||||||
pub async fn register_scholarship(provider_id: String) -> Result<String, ServerFnError> {
|
pub async fn register_scholarship(provider_id: String) -> Result<String, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
debug_log!("Creating scholarship for provider with ID {:?}", provider_id);
|
debug_log!(
|
||||||
|
"Creating scholarship for provider with ID {:?}",
|
||||||
|
provider_id
|
||||||
|
);
|
||||||
|
|
||||||
let mut current_uuid = Uuid::new_v4().to_string();
|
let mut current_uuid = Uuid::new_v4().to_string();
|
||||||
let mut item = ExpandableInfo::new(current_uuid.clone());
|
let mut item = ExpandableInfo::new(current_uuid.clone());
|
||||||
item.data.insert("provider_id".to_string(), ValueType::String(Some(provider_id)));
|
item.data.insert(
|
||||||
|
"provider_id".to_string(),
|
||||||
|
ValueType::String(Some(provider_id)),
|
||||||
|
);
|
||||||
loop {
|
loop {
|
||||||
let ser_item = serde_dynamo::to_item(&item)?;
|
let ser_item = serde_dynamo::to_item(&item)?;
|
||||||
match client
|
match client
|
||||||
@@ -165,10 +179,12 @@ pub async fn register_scholarship(provider_id: String) -> Result<String, ServerF
|
|||||||
log!("Current error: {:?}", err);
|
log!("Current error: {:?}", err);
|
||||||
current_uuid = Uuid::new_v4().to_string();
|
current_uuid = Uuid::new_v4().to_string();
|
||||||
item.subject = current_uuid.clone();
|
item.subject = current_uuid.clone();
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ServerFnError::new(err.message().unwrap_or("An unknown error occurred")));
|
return Err(ServerFnError::new(
|
||||||
|
err.message().unwrap_or("Unknown error occurred"),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,41 +194,51 @@ pub async fn register_scholarship(provider_id: String) -> Result<String, ServerF
|
|||||||
|
|
||||||
/// Deletes a provider's scholarship given their provider ID and scholarship ID.
|
/// Deletes a provider's scholarship given their provider ID and scholarship ID.
|
||||||
#[server(DeleteProviderScholarship)]
|
#[server(DeleteProviderScholarship)]
|
||||||
pub async fn delete_provider_scholarship(provider_id: String, scholarship_id: String) -> Result<(), ServerFnError> {
|
pub async fn delete_provider_scholarship(
|
||||||
|
provider_id: String,
|
||||||
|
scholarship_id: String,
|
||||||
|
) -> Result<(), ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
debug_log!("Deleting scholarship with ID {:?} for provider with ID {:?}", scholarship_id, provider_id);
|
debug_log!(
|
||||||
|
"Deleting scholarship with ID {:?} for provider with ID {:?}",
|
||||||
|
scholarship_id,
|
||||||
|
provider_id
|
||||||
|
);
|
||||||
|
|
||||||
// When we delete a scholarship, we need to ensure that the provider's ID matches the scholarship,
|
// When we delete a scholarship, we need to ensure that the provider's ID matches the scholarship,
|
||||||
// otherwise everyone can delete anyone else's scholarships.
|
// otherwise everyone can delete anyone else's scholarships.
|
||||||
match client
|
match client
|
||||||
.delete_item()
|
.delete_item()
|
||||||
.table_name(SCHOLARSHIPS_TABLE)
|
.table_name(SCHOLARSHIPS_TABLE)
|
||||||
.key("subject", AttributeValue::S(scholarship_id))
|
.key("subject", AttributeValue::S(scholarship_id))
|
||||||
.expression_attribute_values(":provider_id", serde_dynamo::to_attribute_value(ValueType::String(Some(provider_id)))?)
|
.expression_attribute_values(
|
||||||
|
":provider_id",
|
||||||
|
serde_dynamo::to_attribute_value(ValueType::String(Some(provider_id)))?,
|
||||||
|
)
|
||||||
.condition_expression("provider_id = :provider_id")
|
.condition_expression("provider_id = :provider_id")
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(_) => {
|
Ok(_) => Ok(()),
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let msg = err.message().unwrap_or("An unknown error occurred");
|
let msg = err.message().unwrap_or("Unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
Err(ServerFnError::new(msg))
|
Err(ServerFnError::new(msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn get_all_scholarships() -> Result<Vec<std::collections::HashMap<String, crate::common::ValueType>>, ServerFnError> {
|
pub async fn get_all_scholarships()
|
||||||
|
-> Result<Vec<std::collections::HashMap<String, crate::common::ValueType>>, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
client
|
client
|
||||||
.scan()
|
.scan()
|
||||||
.table_name(SCHOLARSHIPS_TABLE)
|
.table_name(SCHOLARSHIPS_TABLE)
|
||||||
@@ -222,12 +248,20 @@ pub async fn get_all_scholarships() -> Result<Vec<std::collections::HashMap<Stri
|
|||||||
let Some(items) = output.items else {
|
let Some(items) = output.items else {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
items.iter().map(|item| {
|
items
|
||||||
// Each item should be simply converted from an AttributeValue to a ValueType.
|
.iter()
|
||||||
item.iter().map(|(k, v)| (k.clone(), ValueType::from(v)))
|
.map(|item| {
|
||||||
.collect::<HashMap<String, ValueType>>()
|
// Each item should be simply converted from an AttributeValue to a ValueType.
|
||||||
}).collect::<Vec<_>>()
|
item.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), ValueType::from(v)))
|
||||||
|
.collect::<HashMap<String, ValueType>>()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
let msg = err.message().unwrap_or("Unknown error occurred");
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
})
|
})
|
||||||
.map_err(ServerFnError::from)
|
|
||||||
}
|
}
|
||||||
+54
-35
@@ -3,36 +3,34 @@ use leptos::server_fn::codec::Json;
|
|||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
mod imports {
|
mod imports {
|
||||||
pub use crate::utils::server::*;
|
|
||||||
pub use aws_sdk_dynamodb::types::AttributeValue;
|
|
||||||
pub use super::super::MAIN_TABLE_NAME;
|
pub use super::super::MAIN_TABLE_NAME;
|
||||||
pub use crate::common::ValueType;
|
pub use crate::common::ValueType;
|
||||||
|
pub use crate::utils::server::*;
|
||||||
|
pub use aws_sdk_dynamodb::error::ProvideErrorMetadata;
|
||||||
|
pub use aws_sdk_dynamodb::types::AttributeValue;
|
||||||
|
pub use leptos::logging::{debug_log, error};
|
||||||
pub use std::collections::HashMap;
|
pub use std::collections::HashMap;
|
||||||
pub use leptos::logging::debug_log;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server(input = Json)]
|
#[server(input = Json)]
|
||||||
pub async fn put_student_data(
|
pub async fn put_student_data(
|
||||||
subject: String,
|
subject: String,
|
||||||
data_type: String,
|
data_type: String,
|
||||||
data_map: std::collections::HashMap<String, crate::common::ValueType>
|
data_map: std::collections::HashMap<String, crate::common::ValueType>,
|
||||||
) -> Result<(), ServerFnError> {
|
) -> Result<(), ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
let mut data_map_attr = into_attr_map(data_map);
|
let mut data_map_attr = into_attr_map(data_map);
|
||||||
data_map_attr.insert(
|
data_map_attr.insert(
|
||||||
"HK".into(),
|
"HK".into(),
|
||||||
AttributeValue::S(format!("STUDENT#{}", subject))
|
AttributeValue::S(format!("STUDENT#{}", subject)),
|
||||||
);
|
);
|
||||||
data_map_attr.insert(
|
data_map_attr.insert("SK".into(), AttributeValue::S(data_type.to_uppercase()));
|
||||||
"SK".into(),
|
|
||||||
AttributeValue::S(data_type.to_uppercase())
|
|
||||||
);
|
|
||||||
|
|
||||||
debug_log!("Inserting this item: {:?}", data_map_attr);
|
debug_log!("Inserting this item: {:?}", data_map_attr);
|
||||||
|
|
||||||
client
|
client
|
||||||
.put_item()
|
.put_item()
|
||||||
.table_name(MAIN_TABLE_NAME)
|
.table_name(MAIN_TABLE_NAME)
|
||||||
@@ -40,7 +38,14 @@ pub async fn put_student_data(
|
|||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(ServerFnError::from)
|
.map_err(|err| {
|
||||||
|
let msg = format!(
|
||||||
|
"Couldn't put item into Dynamo: {}",
|
||||||
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[server]
|
#[server]
|
||||||
@@ -49,9 +54,9 @@ pub async fn get_student_data(
|
|||||||
data_type: String,
|
data_type: String,
|
||||||
) -> Result<std::collections::HashMap<String, crate::common::ValueType>, ServerFnError> {
|
) -> Result<std::collections::HashMap<String, crate::common::ValueType>, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
client
|
client
|
||||||
.query()
|
.query()
|
||||||
.table_name(MAIN_TABLE_NAME)
|
.table_name(MAIN_TABLE_NAME)
|
||||||
@@ -65,37 +70,42 @@ pub async fn get_student_data(
|
|||||||
let Some(list) = output.items else {
|
let Some(list) = output.items else {
|
||||||
return HashMap::new();
|
return HashMap::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
let _ = list
|
let _ = list.into_iter().flatten().for_each(|(k, v)| {
|
||||||
.into_iter()
|
map.insert(k, ValueType::from(&v));
|
||||||
.flatten()
|
});
|
||||||
.for_each(|(k, v)| {
|
|
||||||
map.insert(k, ValueType::from(&v));
|
|
||||||
});
|
|
||||||
|
|
||||||
map
|
map
|
||||||
})
|
})
|
||||||
.map_err(ServerFnError::from)
|
.map_err(|err| {
|
||||||
|
let msg = format!(
|
||||||
|
"Couldn't get item from Dynamo: {}",
|
||||||
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets and flattens all of a student's information from the database, regardless of their defined
|
/// Gets and flattens all of a student's information from the database, regardless of their defined
|
||||||
/// sort key.
|
/// sort key.
|
||||||
///
|
///
|
||||||
/// Note: if sorted data from the `put_student_data` function contains the same fields, this
|
/// Note: if sorted data from the `put_student_data` function contains the same fields, this
|
||||||
/// function will have unexpected behavior. For example, if a `first_name` field appears in multiple
|
/// function will have unexpected behavior. For example, if a `first_name` field appears in multiple
|
||||||
/// locations in the database, all for this single student, they will overwrite each other in no
|
/// locations in the database, all for this single student, they will overwrite each other in no
|
||||||
/// specific order.
|
/// specific order.
|
||||||
#[server]
|
#[server]
|
||||||
pub async fn get_all_student_data(
|
pub async fn get_all_student_data(
|
||||||
subject: String
|
subject: String,
|
||||||
) -> Result<std::collections::HashMap<String, crate::common::ValueType>, ServerFnError> {
|
) -> Result<std::collections::HashMap<String, crate::common::ValueType>, ServerFnError> {
|
||||||
use imports::*;
|
use imports::*;
|
||||||
|
|
||||||
let client = create_dynamo_client().await;
|
let client = create_dynamo_client().await;
|
||||||
|
|
||||||
client.query()
|
client
|
||||||
|
.query()
|
||||||
.table_name(MAIN_TABLE_NAME)
|
.table_name(MAIN_TABLE_NAME)
|
||||||
.key_condition_expression("HK = :hk")
|
.key_condition_expression("HK = :hk")
|
||||||
.expression_attribute_values(":hk", AttributeValue::S(format!("STUDENT#{}", subject)))
|
.expression_attribute_values(":hk", AttributeValue::S(format!("STUDENT#{}", subject)))
|
||||||
@@ -105,10 +115,19 @@ pub async fn get_all_student_data(
|
|||||||
let Some(items) = output.items else {
|
let Some(items) = output.items else {
|
||||||
return HashMap::new();
|
return HashMap::new();
|
||||||
};
|
};
|
||||||
|
|
||||||
items.iter().flatten()
|
items
|
||||||
.map(|(|k, v)| (k.clone(), ValueType::from(v)))
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.map(|(k, v)| (k.clone(), ValueType::from(v)))
|
||||||
.collect::<HashMap<String, ValueType>>()
|
.collect::<HashMap<String, ValueType>>()
|
||||||
})
|
})
|
||||||
.map_err(ServerFnError::from)
|
.map_err(|err| {
|
||||||
|
let msg = format!(
|
||||||
|
"Couldn't get data from Dynamo: {}",
|
||||||
|
err.message().unwrap_or("Unknown error occurred")
|
||||||
|
);
|
||||||
|
error!("{}", msg);
|
||||||
|
ServerFnError::new(msg)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,8 @@ pub fn StudentAthleticsPage() -> impl IntoView {
|
|||||||
"Lacrosse",
|
"Lacrosse",
|
||||||
"Softball",
|
"Softball",
|
||||||
"Tennis",
|
"Tennis",
|
||||||
"Baseball"
|
"Baseball",
|
||||||
|
"Volleyball"
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
input!(
|
input!(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::pages::api::files::list_files;
|
|||||||
use crate::pages::api::students::get_all_student_data;
|
use crate::pages::api::students::get_all_student_data;
|
||||||
use crate::pages::api::{get_all_scholarship_info, get_comparison_info};
|
use crate::pages::api::{get_all_scholarship_info, get_comparison_info};
|
||||||
use crate::utils::get_user_claims;
|
use crate::utils::get_user_claims;
|
||||||
use leptos::logging::debug_log;
|
use leptos::logging::{debug_log, debug_error};
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use leptos_oidc::AuthSignal;
|
use leptos_oidc::AuthSignal;
|
||||||
|
|
||||||
@@ -63,8 +63,7 @@ pub fn StudentEligibilityPage() -> impl IntoView {
|
|||||||
.get("name")
|
.get("name")
|
||||||
.unwrap_or(&ValueType::String(None))
|
.unwrap_or(&ValueType::String(None))
|
||||||
.as_string()
|
.as_string()
|
||||||
.ok()
|
.ok()?
|
||||||
.flatten()
|
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
debug_log!("Checking scholarship: {}", scholarship_name);
|
debug_log!("Checking scholarship: {}", scholarship_name);
|
||||||
let requirements_map = scholarship
|
let requirements_map = scholarship
|
||||||
@@ -72,8 +71,7 @@ pub fn StudentEligibilityPage() -> impl IntoView {
|
|||||||
.get("requirements")
|
.get("requirements")
|
||||||
.unwrap_or(&ValueType::Map(None))
|
.unwrap_or(&ValueType::Map(None))
|
||||||
.as_map()
|
.as_map()
|
||||||
.ok()
|
.ok()?
|
||||||
.flatten()
|
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.values()
|
.values()
|
||||||
.cloned()
|
.cloned()
|
||||||
@@ -104,20 +102,34 @@ pub fn StudentEligibilityPage() -> impl IntoView {
|
|||||||
debug_log!(
|
debug_log!(
|
||||||
"Resolved requirements: {:?}", resolved_requirements.iter().flatten().map(|rel| rel.display_text.clone()).collect::<Vec<String>>()
|
"Resolved requirements: {:?}", resolved_requirements.iter().flatten().map(|rel| rel.display_text.clone()).collect::<Vec<String>>()
|
||||||
);
|
);
|
||||||
let valid = resolved_requirements
|
let valid = !scholarship_name.is_empty()
|
||||||
.iter()
|
&& resolved_requirements
|
||||||
.all(|list| {
|
.iter()
|
||||||
list.iter()
|
.all(|list| {
|
||||||
.fold(
|
debug_log!("Checking list: {:?}", list);
|
||||||
false,
|
if list.is_empty() {
|
||||||
|prev, requirement| {
|
true
|
||||||
let result = requirement
|
} else {
|
||||||
.compare(&student_info)
|
list.iter()
|
||||||
.unwrap_or(false);
|
.any(
|
||||||
if prev { prev } else { result }
|
|requirement| {
|
||||||
},
|
let result = requirement
|
||||||
)
|
.compare(&student_info);
|
||||||
});
|
|
||||||
|
match result.as_ref() {
|
||||||
|
Ok(status) => {
|
||||||
|
debug_log!("Requirement with id {} is Ok({})", requirement.id, status);
|
||||||
|
status.clone()
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
debug_error!("Requirement with id {} failed: {}", requirement.id, e);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
});
|
||||||
if valid {
|
if valid {
|
||||||
debug_log!("Scholarship is valid.");
|
debug_log!("Scholarship is valid.");
|
||||||
let scholarship_id = StoredValue::new(scholarship.subject.clone());
|
let scholarship_id = StoredValue::new(scholarship.subject.clone());
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub fn StudentExtracurricularsPage() -> impl IntoView {
|
|||||||
<div class="flex flex-1" />
|
<div class="flex flex-1" />
|
||||||
<div class="flex flex-col flex-2 mt-6">
|
<div class="flex flex-col flex-2 mt-6">
|
||||||
<ValidatedForm
|
<ValidatedForm
|
||||||
title="Extracurricular Information"
|
title="Extracurricular and Community Service Information"
|
||||||
description="This information will allow you to be eligible for any scholarships that have specific extracurricular requirements."
|
description="This information will allow you to be eligible for any scholarships that have specific extracurricular requirements."
|
||||||
on_submit=controller.submit_action
|
on_submit=controller.submit_action
|
||||||
disabled=controller.submit_pending
|
disabled=controller.submit_pending
|
||||||
|
|||||||
Reference in new issue
Block a user