feat: add new admin APIs and applicants page
This commit is contained in:
1 parent
26b984904b
commit
3cc67cb9e6
9 files changed
+677
-46
No files matched your search
@@ -66,7 +66,7 @@ pub async fn upload_file(data: MultipartData) -> Result<String, ServerFnError> {
|
||||
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, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
let subject = user_claims.subject;
|
||||
|
||||
let key = format!("{form_id}/{subject}/{input_name}/{file_name}");
|
||||
@@ -157,7 +157,7 @@ pub async fn delete_file(
|
||||
) -> Result<String, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let user_claims = validate_and_get_token_info(access_token).await?;
|
||||
let user_claims = validate_and_get_token_info(access_token, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
let subject = user_claims.subject;
|
||||
|
||||
let entry_hk = format!("STUDENT#{subject}");
|
||||
@@ -226,7 +226,7 @@ pub async fn list_files(
|
||||
) -> Result<Vec<String>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let user_claims = validate_and_get_token_info(access_token).await?;
|
||||
let user_claims = validate_and_get_token_info(access_token, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
let subject = user_claims.subject;
|
||||
|
||||
let entry_hk = format!("STUDENT#{subject}");
|
||||
|
||||
+58
-19
@@ -137,24 +137,41 @@ pub async fn get_all_student_data(
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn get_completed_students(
|
||||
pub async fn provider_get_completed_students(
|
||||
access_token: String,
|
||||
) -> Result<HashMap<String, HashMap<String, crate::common::ValueType>>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let claims = validate_and_get_token_info(access_token, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
if !claims.groups.contains(&"ScholarshipProviders".to_string()) {
|
||||
return Err(ServerFnError::new(
|
||||
"User is not in the ScholarshipProviders group",
|
||||
));
|
||||
}
|
||||
|
||||
get_completed_students().await
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn admin_get_completed_students(
|
||||
access_token: String,
|
||||
) -> Result<HashMap<String, HashMap<String, crate::common::ValueType>>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let _ = validate_and_get_token_info(access_token, "us-east-1_rvCU4Xy4j", "us-east-1").await?;
|
||||
|
||||
get_completed_students().await
|
||||
}
|
||||
|
||||
#[server]
|
||||
async fn get_completed_students() -> Result<HashMap<String, HashMap<String, crate::common::ValueType>>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
// We want to get all student information. The requirements are that the students have completed
|
||||
// the demographics form - everything else may bed from this.
|
||||
// The easiest way is to get all the information and filter on this side, instead of bookkeeping
|
||||
// on the database's side.
|
||||
|
||||
// We want to verify the access token first, and make sure that the user has the correct access.
|
||||
let claims = validate_and_get_token_info(access_token).await?;
|
||||
if !claims.groups.contains(&"ScholarshipProviders".to_string()) {
|
||||
return Err(ServerFnError::new(
|
||||
"User is not in the ScholarshipProviders group",
|
||||
));
|
||||
}
|
||||
|
||||
let client = create_dynamo_client().await;
|
||||
|
||||
let response = client
|
||||
@@ -229,7 +246,7 @@ pub async fn get_file_by_key(
|
||||
) -> Result<Vec<u8>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let user_claims = validate_and_get_token_info(access_token).await?;
|
||||
let user_claims = validate_and_get_token_info(access_token, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
|
||||
// Check if the user's subject is contained in the file_key (since all files are keyed by the
|
||||
// user's subject)
|
||||
@@ -279,7 +296,7 @@ pub async fn get_student_files(
|
||||
) -> Result<(String, Vec<u8>), ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let claims = validate_and_get_token_info(access_token).await?;
|
||||
let claims = validate_and_get_token_info(access_token, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
|
||||
// Check if the user has permission to get these files.
|
||||
if !claims.groups.contains(&"ScholarshipProviders".to_string()) {
|
||||
@@ -420,19 +437,12 @@ pub async fn get_student_files(
|
||||
///
|
||||
/// This is only usable by users with provider-level access.
|
||||
#[server]
|
||||
pub async fn get_all_input_files(
|
||||
access_token: String,
|
||||
async fn get_all_input_files(
|
||||
form_name: String,
|
||||
input_name: String,
|
||||
) -> Result<HashMap<String, Vec<String>>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let claims = validate_and_get_token_info(access_token).await?;
|
||||
|
||||
if !claims.groups.contains(&"ScholarshipProviders".to_string()) {
|
||||
return Err(ServerFnError::new("Access denied: user is not a provider"));
|
||||
}
|
||||
|
||||
let client = create_dynamo_client().await;
|
||||
|
||||
let res = client
|
||||
@@ -473,3 +483,32 @@ pub async fn get_all_input_files(
|
||||
|
||||
Ok(result_map)
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn admin_get_all_input_files(
|
||||
access_token: String,
|
||||
form_name: String,
|
||||
input_name: String,
|
||||
) -> Result<HashMap<String, Vec<String>>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let _ = validate_and_get_token_info(access_token, "us-east-1_rvCU4Xy4j", "us-east-1").await?;
|
||||
|
||||
get_all_input_files(form_name, input_name).await
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn provider_get_all_input_files(
|
||||
access_token: String,
|
||||
form_name: String,
|
||||
input_name: String,
|
||||
) -> Result<HashMap<String, Vec<String>>, ServerFnError> {
|
||||
use imports::*;
|
||||
|
||||
let claims = validate_and_get_token_info(access_token, "us-east-1_Lfjuy5zaM", "us-east-1").await?;
|
||||
if !claims.groups.contains(&"ScholarshipProviders".to_string()) {
|
||||
return Err(ServerFnError::new("Access denied: user is not a provider"));
|
||||
}
|
||||
|
||||
get_all_input_files(form_name, input_name).await
|
||||
}
|
||||
+11
-2
@@ -17,10 +17,19 @@ pub async fn fetch_jwks(user_pool_id: String, region: String) -> Result<JwkSet,
|
||||
|
||||
/// Validates a JWT, and, if successful, decodes it into a series of user claims.
|
||||
#[cfg(feature = "ssr")]
|
||||
pub async fn validate_and_get_token_info(token: String) -> Result<UserClaims, ServerFnError> {
|
||||
pub async fn validate_and_get_token_info(
|
||||
token: String,
|
||||
pool_id: impl Into<String>,
|
||||
pool_region: impl Into<String>
|
||||
) -> Result<UserClaims, ServerFnError> {
|
||||
use jsonwebtoken::{Algorithm, Validation, decode};
|
||||
|
||||
let jwks = fetch_jwks("us-east-1_Lfjuy5zaM".into(), "us-east-1".into()).await?;
|
||||
let pool_id = pool_id.into();
|
||||
|
||||
leptos::logging::debug_log!("Validating token using group {}", pool_id);
|
||||
|
||||
// let jwks = fetch_jwks("us-east-1_Lfjuy5zaM".into(), "us-east-1".into()).await?;
|
||||
let jwks = fetch_jwks(pool_id, pool_region.into()).await?;
|
||||
|
||||
let validation = Validation::new(Algorithm::RS256);
|
||||
// validation.set_audience(&["scholarships-rs"]);
|
||||
|
||||
Reference in new issue
Block a user