diff --git a/src/app.rs b/src/app.rs
index b8d691a..0250a79 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -3,9 +3,9 @@ use crate::components::login::ProviderLoginContext;
use crate::pages::{
AdminHomePage, AdminProviderPage, AdminScholarshipPage, AdminShell, AdminUtilsPage,
ApplicantsPageFallback, AuthCallbackPage, LoanerBorrowForm, LoanerFallback, LoanerReturnForm,
- LoanerShell, ProviderContactPage, ProviderPortal, ScholarshipInfoPage,
+ LoanerShell, ProviderContactPage, ProviderPortal,
};
-use crate::pages::{ApplicantsPageShell, student};
+use crate::pages::{FormClosedPage, ApplicantsPageShell, student};
use leptos::prelude::*;
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
use leptos_oidc::AuthSignal;
@@ -91,11 +91,11 @@ fn ProviderRoutes() -> impl MatchNestedRoutes + Clone {
- //
-
-
-
-
+
+ //
+ //
+ //
+ //
}
.into_inner()
diff --git a/src/components/file_drop.rs b/src/components/file_drop.rs
index e83092f..ccbbf96 100644
--- a/src/components/file_drop.rs
+++ b/src/components/file_drop.rs
@@ -1,6 +1,6 @@
use crate::pages::api::files::{DeleteFile, upload_file};
use leptos::html::{Input, Label};
-use leptos::logging::debug_log;
+use leptos::logging::{debug_error, debug_log};
use leptos::prelude::*;
use leptos::web_sys::{File, FormData};
use leptos_icons::Icon;
@@ -28,6 +28,7 @@ pub fn FileDrop(
let file_name_list = RwSignal::new(Vec::new());
let hovering = RwSignal::new(false);
+ let error_msg = RwSignal::new(String::new());
let name = StoredValue::new(name);
let form_id = StoredValue::new(form_id);
let auth = expect_context::();
@@ -172,10 +173,18 @@ pub fn FileDrop(
existing_files
.get()
.map(|result| {
- if let Ok(files) = result {
- file_name_list.set(files);
+ match result {
+ Ok(files) => {
+ error_msg.set("".to_string());
+ file_name_list.set(files);
+ }
+ Err(err) => {
+ let msg = err.to_string();
+ debug_error!("Error while getting files: {}", msg);
+ error_msg.set(msg);
+ }
}
- })
+ });
}}
+
+ {error_msg}
+
Result<(), ServerFnError> {
.await
{
let msg = err.message().unwrap_or("An unknown error occurred");
+ leptos::logging::error!("{}", msg);
return Err(ServerFnError::new(msg));
}
}
@@ -453,7 +454,6 @@ pub async fn get_comparison_info() -> Result, ServerFnError>
match client.scan().table_name(COMPARISONS_TABLE).send().await {
Ok(output) => {
if let Some(items) = output.items {
- log!("Found comparisons from API: {:?}", items);
Ok(serde_dynamo::from_items(items)?)
} else {
Ok(vec![])
@@ -461,6 +461,7 @@ pub async fn get_comparison_info() -> Result, ServerFnError>
}
Err(err) => {
let msg = err.message().unwrap_or("An unknown error occurred");
+ leptos::logging::error!("{}", msg);
Err(ServerFnError::new(msg))
}
}
@@ -493,11 +494,14 @@ pub async fn get_comparisons_categorized()
Ok(categorized)
} 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) => {
let msg = err.message().unwrap_or("An unknown error occurred");
+ leptos::logging::error!("{}", msg);
Err(ServerFnError::new(msg))
}
}
diff --git a/src/pages/api/dates.rs b/src/pages/api/dates.rs
index 3cbf387..2b34833 100644
--- a/src/pages/api/dates.rs
+++ b/src/pages/api/dates.rs
@@ -1,61 +1,60 @@
-use std::collections::HashMap;
-use leptos::logging::log;
-use leptos::prelude::*;
use crate::common::DateInfo;
+use leptos::logging::{error, log};
+use leptos::prelude::*;
+use std::collections::HashMap;
#[cfg(feature = "ssr")]
use super::DATES_TABLE;
-#[cfg(feature = "ssr")]
-use aws_sdk_dynamodb::{
- types::{WriteRequest, PutRequest},
- Client as DynamoClient
-};
-
#[cfg(feature = "ssr")]
use crate::utils::server::create_dynamo_client;
-
#[cfg(feature = "ssr")]
-use std::sync::Arc;
+use aws_sdk_dynamodb::{
+ Client as DynamoClient,
+ error::ProvideErrorMetadata,
+ types::{PutRequest, WriteRequest},
+};
#[server]
pub async fn create_dates(dates: Vec) -> Result<(), ServerFnError> {
// Serialize and put dates into the database.
let client = create_dynamo_client().await;
-
+
log!("Creating dates: {:?}", dates);
-
+
let requests = dates
.into_iter()
- .map(|date| {
- let item = serde_dynamo::to_item(&date)
- .unwrap_or_default();
-
- let put_request = PutRequest::builder()
- .set_item(Some(item))
- .build()
- .expect("Couldn't build request, item is not present");
-
- WriteRequest::builder().put_request(put_request).build()
+ .filter_map(|date| {
+ let item = serde_dynamo::to_item(&date).unwrap_or_default();
+
+ let put_request = PutRequest::builder().set_item(Some(item)).build().ok()?;
+
+ Some(WriteRequest::builder().put_request(put_request).build())
})
.collect::>();
-
+
let mut request_map = HashMap::new();
request_map.insert(DATES_TABLE.to_string(), requests);
-
+
client
.batch_write_item()
.set_request_items(Some(request_map))
.send()
.await
.map(|_| ())
- .map_err(ServerFnError::from)
+ .map_err(|err| {
+ let msg = err.message().unwrap_or("Unknown error occurred");
+ error!("{}", msg);
+ ServerFnError::new(msg)
+ })
}
#[server]
pub async fn get_important_dates() -> Result, ServerFnError> {
+ log!("Getting important dates list");
+
let client = create_dynamo_client().await;
-
+
client
.scan()
.table_name(DATES_TABLE)
@@ -65,14 +64,15 @@ pub async fn get_important_dates() -> Result, ServerFnError> {
if let Some(items) = output.items {
items
.into_iter()
- .filter_map(|item| {
- serde_dynamo::from_item::<_, DateInfo>(item)
- .ok()
- })
+ .filter_map(|item| serde_dynamo::from_item::<_, DateInfo>(item).ok())
.collect::>()
} else {
Vec::new()
}
})
- .map_err(ServerFnError::from)
+ .map_err(|err| {
+ let msg = err.message().unwrap_or("Unknown error occurred");
+ error!("{}", msg);
+ ServerFnError::new(msg)
+ })
}
diff --git a/src/pages/api/exports.rs b/src/pages/api/exports.rs
index 54a39f3..324ac59 100644
--- a/src/pages/api/exports.rs
+++ b/src/pages/api/exports.rs
@@ -231,7 +231,6 @@ pub async fn get_scholarship_csv() -> Result, ServerFnError> {
writer.flush()?;
let result = writer.into_inner()?;
- debug_log!("{:?}", String::from_utf8(result.clone()));
Ok(result)
}
diff --git a/src/pages/api/files.rs b/src/pages/api/files.rs
index 9692b7f..aac22b9 100644
--- a/src/pages/api/files.rs
+++ b/src/pages/api/files.rs
@@ -1,4 +1,5 @@
-use leptos::logging::debug_log;
+use leptos::leptos_dom::error;
+use leptos::logging::debug_log;
use leptos::prelude::*;
use server_fn::codec::{MultipartData, MultipartFormData};
@@ -83,10 +84,12 @@ pub async fn upload_file(data: MultipartData) -> Result {
.await
.map(|_| ())
.map_err(|e| {
- ServerFnError::new(format!(
+ let msg = format!(
"Couldn't put file to S3: {}",
- e.message().unwrap_or_default()
- ))
+ 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.
@@ -113,11 +116,13 @@ pub async fn upload_file(data: MultipartData) -> Result {
.item("file_key".to_string(), AttributeValue::S(key.clone()))
.send()
.await
- .map_err(|e| {
- ServerFnError::new(format!(
+ .map_err(|err| {
+ let msg = format!(
"Couldn't put file to Dynamo, file rolled back: {}",
- e.message().unwrap_or_default()
- ))
+ 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.
@@ -128,11 +133,13 @@ pub async fn upload_file(data: MultipartData) -> Result {
.key(&key)
.send()
.await
- .map_err(|e| {
- ServerFnError::new(format!(
- "Couldn't roll back S3 operation: {}",
- e.message().unwrap_or_default()
- ))
+ .map_err(|err| {
+ let msg = format!(
+ "Failed to rollback Dynamo entry: {}",
+ err.message().unwrap_or("Unknown error occurred")
+ );
+ error!("{}", msg);
+ ServerFnError::new(msg)
})?;
return Err(err);
@@ -179,7 +186,14 @@ pub async fn delete_file(
.key(key)
.send()
.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 {
// Add the key back to Dynamo and return an error.
@@ -190,10 +204,12 @@ pub async fn delete_file(
.send()
.await
.map_err(|err| {
- ServerFnError::new(format!(
- "Couldn't roll back Dynamo operation: {}",
- err.message().unwrap_or_default()
- ))
+ let msg = format!(
+ "Failed to rollback Dynamo entry: {}",
+ err.message().unwrap_or("Unknown error occurred")
+ );
+ error!("{}", msg);
+ ServerFnError::new(msg)
})?;
return Err(err);
@@ -242,10 +258,12 @@ pub async fn list_files(
})
.collect::>()
})
- .map_err(|e| {
- ServerFnError::new(format!(
- "Couldn't list files: {}",
- e.message().unwrap_or_default()
- ))
+ .map_err(|err| {
+ let msg = format!(
+ "Failed to get files: {}",
+ err.message().unwrap_or("Unknown error occurred")
+ );
+ error!("{}", msg);
+ ServerFnError::new(msg)
})
}
diff --git a/src/pages/api/providers.rs b/src/pages/api/providers.rs
index 988e932..071def2 100644
--- a/src/pages/api/providers.rs
+++ b/src/pages/api/providers.rs
@@ -1,8 +1,8 @@
-use leptos::prelude::*;
-use leptos::logging::debug_log;
-use std::collections::HashMap;
+use crate::common::ValueType;
+use leptos::logging::{debug_log, error};
+use leptos::prelude::*;
use leptos::server_fn::codec::Json;
-use crate::common::ValueType;
+use std::collections::HashMap;
#[cfg(feature = "ssr")]
use crate::utils::server::{create_dynamo_client, into_attr_map};
@@ -12,8 +12,8 @@ static PROVIDER_CONTACT_TABLE: &str = "leptos-provider-contacts";
#[server]
pub async fn get_provider_contact(id: String) -> Result, ServerFnError> {
- use aws_sdk_dynamodb::types::AttributeValue;
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
+ use aws_sdk_dynamodb::types::AttributeValue;
let client = create_dynamo_client().await;
@@ -31,29 +31,39 @@ pub async fn get_provider_contact(id: String) -> Result>();
+ (key.clone(), val_type)
+ })
+ .collect::>();
Ok(map)
}
Err(err) => {
let msg = err.message().unwrap_or("An unknown error occurred.");
+ error!("{}", msg);
Err(ServerFnError::new(msg))
}
}
}
#[server(input = Json)]
-pub async fn put_provider_contact(id: String, contact_info: HashMap) -> Result<(), ServerFnError> {
+pub async fn put_provider_contact(
+ id: String,
+ contact_info: HashMap,
+) -> Result<(), ServerFnError> {
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
let client = create_dynamo_client().await;
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
.put_item()
@@ -65,7 +75,8 @@ pub async fn put_provider_contact(id: String, contact_info: HashMap Ok(()),
Err(err) => {
let msg = err.message().unwrap_or("An unknown error occurred.");
+ error!("{}", msg);
Err(ServerFnError::new(msg))
}
}
-}
\ No newline at end of file
+}
diff --git a/src/pages/api/scholarships.rs b/src/pages/api/scholarships.rs
index a7764de..1bc7069 100644
--- a/src/pages/api/scholarships.rs
+++ b/src/pages/api/scholarships.rs
@@ -1,15 +1,11 @@
#[cfg(feature = "ssr")]
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 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;
@@ -20,7 +16,7 @@ use leptos::server_fn::codec::Json;
#[server(GetScholarshipInfo)]
pub async fn get_scholarship_info(id: String) -> Result {
use imports::*;
-
+
let client = create_dynamo_client().await;
// 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 {
let msg = err.message().unwrap_or("An unknown error occurred");
+ error!("{}", msg);
Err(ServerFnError::new(msg))
}
}
@@ -51,12 +50,15 @@ pub async fn get_scholarship_info(id: String) -> Result Result<(), ServerFnError> {
- use imports::*;
use aws_sdk_dynamodb::error::ProvideErrorMetadata;
+ use imports::*;
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
.put_item()
@@ -68,6 +70,7 @@ pub async fn create_scholarship_info(info: ExpandableInfo) -> Result<(), ServerF
Ok(_) => Ok(()),
Err(err) => {
let msg = err.message().unwrap_or("An unknown error occurred");
+ error!("{}", msg);
Err(ServerFnError::new(msg))
}
}
@@ -76,24 +79,20 @@ pub async fn create_scholarship_info(info: ExpandableInfo) -> Result<(), ServerF
#[server(GetAllScholarshipInfo)]
pub async fn get_all_scholarship_info() -> Result, ServerFnError> {
use imports::*;
-
+
let client = create_dynamo_client().await;
debug_log!("Getting all scholarship info");
- match client
- .scan()
- .table_name(SCHOLARSHIPS_TABLE)
- .send()
- .await
- {
+ match client.scan().table_name(SCHOLARSHIPS_TABLE).send().await {
Ok(output) => {
if let Some(items) = output.items {
Ok(serde_dynamo::from_items(items)?)
} else {
Ok(Vec::new())
}
- },
+ }
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))
}
}
@@ -101,17 +100,25 @@ pub async fn get_all_scholarship_info() -> Result, ServerFnE
/// Gets all scholarships that are associated with the given scholarship provider's ID.
#[server(GetProviderScholarships)]
-pub async fn get_provider_scholarships(provider_id: String) -> Result, ServerFnError> {
+pub async fn get_provider_scholarships(
+ provider_id: String,
+) -> Result, ServerFnError> {
use imports::*;
-
+
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
.scan()
.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")
.send()
.await
@@ -124,7 +131,8 @@ pub async fn get_provider_scholarships(provider_id: String) -> Result {
- 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))
}
}
@@ -134,14 +142,20 @@ pub async fn get_provider_scholarships(provider_id: String) -> Result Result {
use imports::*;
-
+
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 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 {
let ser_item = serde_dynamo::to_item(&item)?;
match client
@@ -165,10 +179,12 @@ pub async fn register_scholarship(provider_id: String) -> Result {
- 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 Result<(), ServerFnError> {
+pub async fn delete_provider_scholarship(
+ provider_id: String,
+ scholarship_id: String,
+) -> Result<(), ServerFnError> {
use imports::*;
-
+
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,
// otherwise everyone can delete anyone else's scholarships.
match client
.delete_item()
.table_name(SCHOLARSHIPS_TABLE)
.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")
.send()
.await
{
- Ok(_) => {
- Ok(())
- }
+ Ok(_) => Ok(()),
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))
}
}
}
#[server]
-pub async fn get_all_scholarships() -> Result>, ServerFnError> {
+pub async fn get_all_scholarships()
+-> Result>, ServerFnError> {
use imports::*;
use std::collections::HashMap;
-
+
let client = create_dynamo_client().await;
-
+
client
.scan()
.table_name(SCHOLARSHIPS_TABLE)
@@ -222,12 +248,20 @@ pub async fn get_all_scholarships() -> Result>()
- }).collect::>()
+
+ items
+ .iter()
+ .map(|item| {
+ // Each item should be simply converted from an AttributeValue to a ValueType.
+ item.iter()
+ .map(|(k, v)| (k.clone(), ValueType::from(v)))
+ .collect::>()
+ })
+ .collect::>()
+ })
+ .map_err(|err| {
+ let msg = err.message().unwrap_or("Unknown error occurred");
+ error!("{}", msg);
+ ServerFnError::new(msg)
})
- .map_err(ServerFnError::from)
}
diff --git a/src/pages/api/students.rs b/src/pages/api/students.rs
index f5d7eb1..c18f657 100644
--- a/src/pages/api/students.rs
+++ b/src/pages/api/students.rs
@@ -3,36 +3,34 @@ use leptos::server_fn::codec::Json;
#[cfg(feature = "ssr")]
mod imports {
- pub use crate::utils::server::*;
- pub use aws_sdk_dynamodb::types::AttributeValue;
pub use super::super::MAIN_TABLE_NAME;
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 leptos::logging::debug_log;
}
#[server(input = Json)]
pub async fn put_student_data(
subject: String,
data_type: String,
- data_map: std::collections::HashMap
+ data_map: std::collections::HashMap,
) -> Result<(), ServerFnError> {
use imports::*;
-
+
let client = create_dynamo_client().await;
-
+
let mut data_map_attr = into_attr_map(data_map);
data_map_attr.insert(
"HK".into(),
- AttributeValue::S(format!("STUDENT#{}", subject))
+ AttributeValue::S(format!("STUDENT#{}", subject)),
);
- data_map_attr.insert(
- "SK".into(),
- AttributeValue::S(data_type.to_uppercase())
- );
-
+ data_map_attr.insert("SK".into(), AttributeValue::S(data_type.to_uppercase()));
+
debug_log!("Inserting this item: {:?}", data_map_attr);
-
+
client
.put_item()
.table_name(MAIN_TABLE_NAME)
@@ -40,7 +38,14 @@ pub async fn put_student_data(
.send()
.await
.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]
@@ -49,9 +54,9 @@ pub async fn get_student_data(
data_type: String,
) -> Result, ServerFnError> {
use imports::*;
-
+
let client = create_dynamo_client().await;
-
+
client
.query()
.table_name(MAIN_TABLE_NAME)
@@ -65,37 +70,42 @@ pub async fn get_student_data(
let Some(list) = output.items else {
return HashMap::new();
};
-
+
let mut map = HashMap::new();
-
- let _ = list
- .into_iter()
- .flatten()
- .for_each(|(k, v)| {
- map.insert(k, ValueType::from(&v));
- });
-
+
+ let _ = list.into_iter().flatten().for_each(|(k, v)| {
+ map.insert(k, ValueType::from(&v));
+ });
+
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
/// sort key.
-///
+///
/// 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
/// locations in the database, all for this single student, they will overwrite each other in no
/// specific order.
#[server]
pub async fn get_all_student_data(
- subject: String
+ subject: String,
) -> Result, ServerFnError> {
use imports::*;
-
+
let client = create_dynamo_client().await;
-
- client.query()
+
+ client
+ .query()
.table_name(MAIN_TABLE_NAME)
.key_condition_expression("HK = :hk")
.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 {
return HashMap::new();
};
-
- items.iter().flatten()
- .map(|(|k, v)| (k.clone(), ValueType::from(v)))
+
+ items
+ .iter()
+ .flatten()
+ .map(|(k, v)| (k.clone(), ValueType::from(v)))
.collect::>()
})
- .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)
+ })
}
diff --git a/src/pages/student/eligibility_page.rs b/src/pages/student/eligibility_page.rs
index dadc1ce..f52e681 100644
--- a/src/pages/student/eligibility_page.rs
+++ b/src/pages/student/eligibility_page.rs
@@ -4,7 +4,7 @@ use crate::pages::api::files::list_files;
use crate::pages::api::students::get_all_student_data;
use crate::pages::api::{get_all_scholarship_info, get_comparison_info};
use crate::utils::get_user_claims;
-use leptos::logging::debug_log;
+use leptos::logging::{debug_error, debug_log};
use leptos::prelude::*;
use leptos_oidc::AuthSignal;
@@ -23,6 +23,7 @@ pub fn StudentEligibilityPage() -> impl IntoView {
let auth = expect_context::();
let user_claims = get_user_claims();
let user_id = Memo::new(move |_| user_claims.get().map(|info| info.claims.subject.clone()));
+ let access_token = Memo::new(move |_| auth.get().authenticated().map(|a| a.access_token()));
let form_id = StoredValue::new("scholarship_essays".to_string());
@@ -63,8 +64,7 @@ pub fn StudentEligibilityPage() -> impl IntoView {
.get("name")
.unwrap_or(&ValueType::String(None))
.as_string()
- .ok()
- .flatten()
+ .ok()?
.unwrap_or_default();
debug_log!("Checking scholarship: {}", scholarship_name);
let requirements_map = scholarship
@@ -72,8 +72,7 @@ pub fn StudentEligibilityPage() -> impl IntoView {
.get("requirements")
.unwrap_or(&ValueType::Map(None))
.as_map()
- .ok()
- .flatten()
+ .ok()?
.unwrap_or_default()
.values()
.cloned()
@@ -108,38 +107,44 @@ pub fn StudentEligibilityPage() -> impl IntoView {
&& resolved_requirements
.iter()
.all(|list| {
- list.iter()
- .fold(
- false,
- |prev, requirement| {
- let result = requirement
- .compare(&student_info)
- .unwrap_or_else(|err| {
- debug_log!("Requirement failed: {err}");
+ debug_log!("Checking list: {:?}", list);
+ if list.is_empty() {
+ true
+ } else {
+ list.iter()
+ .any(|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 prev { prev } else { result }
- },
- )
+ }
+ }
+ })
+ }
});
if valid {
debug_log!("Scholarship is valid.");
let scholarship_id = StoredValue::new(scholarship.subject.clone());
let resource = Resource::new(
move || (
- auth
- .try_with(|a| a.authenticated().map(|a| a.access_token()))
- .flatten(),
+ access_token.get(),
form_id.get_value(),
scholarship_id.get_value(),
),
async move |(access_token, form_id, scholarship_id)| {
- list_files(
- access_token.unwrap_or_default(),
- form_id,
- scholarship_id,
- )
- .await
+ let Some(access_token) = access_token else {
+ return Err(ServerFnError::new("Couldn't find access token"));
+ };
+ list_files(access_token, form_id, scholarship_id).await
},
);
Some((scholarship.clone(), resource))
diff --git a/src/pages/student/form_setup.rs b/src/pages/student/form_setup.rs
index 70c5222..6b4f215 100644
--- a/src/pages/student/form_setup.rs
+++ b/src/pages/student/form_setup.rs
@@ -1,10 +1,10 @@
-use std::collections::HashMap;
-use leptos::prelude::*;
-use uuid::Uuid;
use crate::common::ValueType;
use crate::components::{Toast, ToastContext};
-use crate::pages::api::students::{get_student_data, PutStudentData};
+use crate::pages::api::students::{PutStudentData, get_student_data};
use crate::utils::get_user_claims;
+use leptos::prelude::*;
+use std::collections::HashMap;
+use uuid::Uuid;
pub struct StudentFormInfo {
pub data_map: RwSignal>,
@@ -20,22 +20,21 @@ pub fn use_student_form(
enable_toasts: bool,
) -> StudentFormInfo {
let form_type = form_type.into();
-
+
let user_claims = get_user_claims();
- let user_id = Memo::new(move |_| {
- user_claims.get()
- .map(|info| info.claims.subject.clone())
- });
+ let user_id = Memo::new(move |_| user_claims.get().map(|info| info.claims.subject.clone()));
let data_map = RwSignal::new(HashMap::new());
let refresh_trigger = Trigger::new();
let data_resource = Resource::new(
- move || (user_id.get().unwrap_or_default(), form_type.get(), refresh_trigger.track()),
- async move |(id, form_type, _)| get_student_data(
- id,
- form_type,
- ).await
+ move || (user_id.get(), form_type.get(), refresh_trigger.track()),
+ async move |(id, form_type, _)| {
+ let Some(id) = id else {
+ return Ok(HashMap::new());
+ };
+ get_student_data(id, form_type).await
+ },
);
Effect::new(move || {
@@ -50,13 +49,15 @@ pub fn use_student_form(
let submit_action = ServerAction::::new();
let on_submit = move || {
- submit_action.dispatch(PutStudentData {
- subject: user_id.get().unwrap_or_default(),
- data_type: form_type.get(),
- data_map: data_map.get()
- });
+ if let Some(id) = user_id.get() {
+ submit_action.dispatch(PutStudentData {
+ subject: id,
+ data_type: form_type.get(),
+ data_map: data_map.get(),
+ });
+ }
};
-
+
if enable_toasts {
let mut toasts = expect_context::();
Effect::watch(
@@ -74,13 +75,13 @@ pub fn use_student_form(
Err(e) => Toast::new()
.id(Uuid::new_v4())
.header("Submission Failed")
- .msg(e.to_string())
+ .msg(e.to_string()),
};
toasts.toast(toast);
untrack(move || submit_action.clear());
},
- false
+ false,
);
}
@@ -90,6 +91,6 @@ pub fn use_student_form(
data_resource,
user_id,
submit_action: on_submit.into(),
- submit_pending: submit_action.pending()
+ submit_pending: submit_action.pending(),
}
-}
\ No newline at end of file
+}