fix(ws-org): enforce current_org_id for teacher-student APIs
Require organization context in teacher/student relation reads and writes, and prevent fallback to cross-organization queries. Made-with: Cursor
This commit is contained in:
+67
-133
@@ -16,6 +16,10 @@ fn current_org_id_from_token_str(token_str: &String) -> Option<String> {
|
|||||||
.and_then(|decoded| decoded.current_org_id)
|
.and_then(|decoded| decoded.current_org_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn required_current_org_id_from_token_str(token_str: &String) -> anyhow::Result<String> {
|
||||||
|
current_org_id_from_token_str(token_str).ok_or_else(|| anyhow!("current_org_id is required"))
|
||||||
|
}
|
||||||
|
|
||||||
use htycommons::common::{
|
use htycommons::common::{
|
||||||
current_local_datetime, get_page_and_page_size, get_some_from_query_params, strip_result_vec,
|
current_local_datetime, get_page_and_page_size, get_some_from_query_params, strip_result_vec,
|
||||||
HtyErr, HtyErrCode, HtyResponse,
|
HtyErr, HtyErrCode, HtyResponse,
|
||||||
@@ -3142,6 +3146,7 @@ pub async fn raw_get_unclaimed_students(
|
|||||||
host: HtyHostHeader,
|
host: HtyHostHeader,
|
||||||
db_pool: Arc<DbState>,
|
db_pool: Arc<DbState>,
|
||||||
) -> anyhow::Result<Vec<ReqHtyUserWithInfos>> {
|
) -> anyhow::Result<Vec<ReqHtyUserWithInfos>> {
|
||||||
|
let current_org_id = required_current_org_id_from_token_str(&root.0)?;
|
||||||
let url = format!("{}/find_users_with_info_by_role/STUDENT", get_uc_url(),);
|
let url = format!("{}/find_users_with_info_by_role/STUDENT", get_uc_url(),);
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
let ret_json = client
|
let ret_json = client
|
||||||
@@ -3161,11 +3166,12 @@ pub async fn raw_get_unclaimed_students(
|
|||||||
})?;
|
})?;
|
||||||
let mut resp = vec![];
|
let mut resp = vec![];
|
||||||
for user_with_info in user_with_infos {
|
for user_with_info in user_with_infos {
|
||||||
let exist = TeacherStudent::verify_exist_and_not_deleted_by_student_id(
|
let exist = TeacherStudent::verify_exist_and_not_deleted_by_student_id_in_org(
|
||||||
user_with_info
|
user_with_info
|
||||||
.hty_id
|
.hty_id
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.ok_or_else(|| anyhow!("hty_id is required"))?,
|
.ok_or_else(|| anyhow!("hty_id is required"))?,
|
||||||
|
¤t_org_id,
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
)?;
|
)?;
|
||||||
if !exist {
|
if !exist {
|
||||||
@@ -3217,21 +3223,13 @@ pub async fn raw_claim_student(
|
|||||||
.clone()
|
.clone()
|
||||||
.ok_or_else(|| anyhow!("id_student is required"))?;
|
.ok_or_else(|| anyhow!("id_student is required"))?;
|
||||||
|
|
||||||
let current_org_id = current_org_id_from_token_str(&(*token).clone());
|
let current_org_id = required_current_org_id_from_token_str(&(*token).clone())?;
|
||||||
let res_exist = if let Some(org_id) = ¤t_org_id {
|
let res_exist = TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
&id_teacher,
|
||||||
&id_teacher,
|
&id_student,
|
||||||
&id_student,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id(
|
|
||||||
&id_teacher,
|
|
||||||
&id_student,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
if res_exist {
|
if res_exist {
|
||||||
return Err(anyhow!(HtyErr {
|
return Err(anyhow!(HtyErr {
|
||||||
code: HtyErrCode::WebErr,
|
code: HtyErrCode::WebErr,
|
||||||
@@ -3244,7 +3242,7 @@ pub async fn raw_claim_student(
|
|||||||
id: uuid(),
|
id: uuid(),
|
||||||
status: String::from("Approved"),
|
status: String::from("Approved"),
|
||||||
created_at: Some(current_local_datetime()),
|
created_at: Some(current_local_datetime()),
|
||||||
org_id: current_org_id,
|
org_id: Some(current_org_id),
|
||||||
};
|
};
|
||||||
let res = TeacherStudent::create(
|
let res = TeacherStudent::create(
|
||||||
&in_record,
|
&in_record,
|
||||||
@@ -3340,42 +3338,25 @@ pub async fn raw_disclaim_student(
|
|||||||
.clone()
|
.clone()
|
||||||
.ok_or_else(|| anyhow!("id_student is required"))?;
|
.ok_or_else(|| anyhow!("id_student is required"))?;
|
||||||
|
|
||||||
let current_org_id = current_org_id_from_token_str(&(*auth).clone());
|
let current_org_id = required_current_org_id_from_token_str(&(*auth).clone())?;
|
||||||
let res_exist = if let Some(org_id) = ¤t_org_id {
|
let res_exist = TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
&id_teacher,
|
||||||
&id_teacher,
|
&id_student,
|
||||||
&id_student,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id(
|
|
||||||
&id_teacher,
|
|
||||||
&id_student,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
if !res_exist {
|
if !res_exist {
|
||||||
return Err(anyhow!(HtyErr {
|
return Err(anyhow!(HtyErr {
|
||||||
code: HtyErrCode::WebErr,
|
code: HtyErrCode::WebErr,
|
||||||
reason: Some("no existing record for this teacher and student".into()),
|
reason: Some("no existing record for this teacher and student".into()),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let res = if let Some(org_id) = ¤t_org_id {
|
let res = TeacherStudent::del_by_teacher_id_and_student_id_in_org(
|
||||||
TeacherStudent::del_by_teacher_id_and_student_id_in_org(
|
&id_teacher,
|
||||||
&id_teacher,
|
&id_student,
|
||||||
&id_student,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
let record = TeacherStudent::find_by_teacher_id_and_student_id(
|
|
||||||
&id_teacher,
|
|
||||||
&id_student,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?;
|
|
||||||
TeacherStudent::delete_by_id(&record.id, extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?
|
|
||||||
};
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3579,19 +3560,12 @@ pub async fn raw_find_all_teachers_by_student_id(
|
|||||||
student_id: String,
|
student_id: String,
|
||||||
db_pool: Arc<DbState>,
|
db_pool: Arc<DbState>,
|
||||||
) -> anyhow::Result<Vec<ReqHtyUserWithInfos>> {
|
) -> anyhow::Result<Vec<ReqHtyUserWithInfos>> {
|
||||||
let current_org_id = current_org_id_from_token_str(&root.0);
|
let current_org_id = required_current_org_id_from_token_str(&root.0)?;
|
||||||
let teacher_ids = if let Some(org_id) = ¤t_org_id {
|
let teacher_ids = TeacherStudent::get_all_teachers_by_student_id_in_org(
|
||||||
TeacherStudent::get_all_teachers_by_student_id_in_org(
|
&student_id,
|
||||||
&student_id,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::get_all_teachers_by_student_id(
|
|
||||||
&student_id,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
debug!(
|
debug!(
|
||||||
"raw_find_all_teachers_by_student_id -> teacher_ids {:?}",
|
"raw_find_all_teachers_by_student_id -> teacher_ids {:?}",
|
||||||
&teacher_ids
|
&teacher_ids
|
||||||
@@ -3652,21 +3626,13 @@ pub async fn raw_delete_teacher_student(
|
|||||||
let _teacher = find_hty_user_with_info_by_id(&teacher_id, &root).await?;
|
let _teacher = find_hty_user_with_info_by_id(&teacher_id, &root).await?;
|
||||||
let _student = find_hty_user_with_info_by_id(&student_id, &root).await?;
|
let _student = find_hty_user_with_info_by_id(&student_id, &root).await?;
|
||||||
|
|
||||||
let current_org_id = current_org_id_from_token_str(&root.0);
|
let current_org_id = required_current_org_id_from_token_str(&root.0)?;
|
||||||
let is_exist = if let Some(org_id) = ¤t_org_id {
|
let is_exist = TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
&teacher_id,
|
||||||
&teacher_id,
|
&student_id,
|
||||||
&student_id,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id(
|
|
||||||
&teacher_id,
|
|
||||||
&student_id,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
|
|
||||||
if !is_exist {
|
if !is_exist {
|
||||||
return Err(anyhow!(HtyErr {
|
return Err(anyhow!(HtyErr {
|
||||||
@@ -3682,20 +3648,12 @@ pub async fn raw_delete_teacher_student(
|
|||||||
// )?;
|
// )?;
|
||||||
|
|
||||||
// record.status = status;
|
// record.status = status;
|
||||||
if let Some(org_id) = ¤t_org_id {
|
let _ = TeacherStudent::del_by_teacher_id_and_student_id_in_org(
|
||||||
let _ = TeacherStudent::del_by_teacher_id_and_student_id_in_org(
|
&teacher_id,
|
||||||
&teacher_id,
|
&student_id,
|
||||||
&student_id,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
let _ = TeacherStudent::del_by_teacher_id_and_student_id(
|
|
||||||
&teacher_id,
|
|
||||||
&student_id,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3753,41 +3711,25 @@ pub async fn raw_update_teacher_student(
|
|||||||
let _teacher = find_hty_user_with_info_by_id(&teacher_id, &root).await?;
|
let _teacher = find_hty_user_with_info_by_id(&teacher_id, &root).await?;
|
||||||
let _student = find_hty_user_with_info_by_id(&student_id, &root).await?;
|
let _student = find_hty_user_with_info_by_id(&student_id, &root).await?;
|
||||||
|
|
||||||
let current_org_id = current_org_id_from_token_str(&root.0);
|
let current_org_id = required_current_org_id_from_token_str(&root.0)?;
|
||||||
let is_exist = if let Some(org_id) = ¤t_org_id {
|
let is_exist = TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id_in_org(
|
&teacher_id,
|
||||||
&teacher_id,
|
&student_id,
|
||||||
&student_id,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::verify_exist_by_teacher_id_and_student_id(
|
|
||||||
&teacher_id,
|
|
||||||
&student_id,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
if !is_exist {
|
if !is_exist {
|
||||||
return Err(anyhow!(HtyErr {
|
return Err(anyhow!(HtyErr {
|
||||||
code: HtyErrCode::NullErr,
|
code: HtyErrCode::NullErr,
|
||||||
reason: Some("no record for this teacher and student".to_string()),
|
reason: Some("no record for this teacher and student".to_string()),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
let mut record = if let Some(org_id) = ¤t_org_id {
|
let mut record = TeacherStudent::find_by_teacher_id_and_student_id_in_org(
|
||||||
TeacherStudent::find_by_teacher_id_and_student_id_in_org(
|
&teacher_id,
|
||||||
&teacher_id,
|
&student_id,
|
||||||
&student_id,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::find_by_teacher_id_and_student_id(
|
|
||||||
&teacher_id,
|
|
||||||
&student_id,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
record.status = status;
|
record.status = status;
|
||||||
let _ = TeacherStudent::update(&record, extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
let _ = TeacherStudent::update(&record, extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -3834,21 +3776,13 @@ pub async fn raw_find_all_students_by_teacher_id_and_status(
|
|||||||
let status = req_teacher_student
|
let status = req_teacher_student
|
||||||
.status
|
.status
|
||||||
.ok_or_else(|| anyhow!("status is required"))?;
|
.ok_or_else(|| anyhow!("status is required"))?;
|
||||||
let current_org_id = current_org_id_from_token_str(&root.0);
|
let current_org_id = required_current_org_id_from_token_str(&root.0)?;
|
||||||
let student_ids = if let Some(org_id) = ¤t_org_id {
|
let student_ids = TeacherStudent::get_all_students_by_teacher_id_and_status_in_org(
|
||||||
TeacherStudent::get_all_students_by_teacher_id_and_status_in_org(
|
&teacher_id,
|
||||||
&teacher_id,
|
&status,
|
||||||
&status,
|
¤t_org_id,
|
||||||
org_id,
|
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
)?;
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
TeacherStudent::get_all_students_by_teacher_id_and_status(
|
|
||||||
&teacher_id,
|
|
||||||
&status,
|
|
||||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
|
||||||
)?
|
|
||||||
};
|
|
||||||
debug!(
|
debug!(
|
||||||
"raw_find_all_students_by_teacher_id_and_status -> student_ids {:?}",
|
"raw_find_all_students_by_teacher_id_and_status -> student_ids {:?}",
|
||||||
&student_ids
|
&student_ids
|
||||||
|
|||||||
@@ -3087,6 +3087,26 @@ impl TeacherStudent {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn verify_exist_and_not_deleted_by_student_id_in_org(
|
||||||
|
id_student: &String,
|
||||||
|
id_org: &String,
|
||||||
|
conn: &mut PgConnection,
|
||||||
|
) -> anyhow::Result<bool> {
|
||||||
|
use crate::schema::teacher_student::dsl::*;
|
||||||
|
select(exists(
|
||||||
|
teacher_student
|
||||||
|
.filter(student_id.eq(id_student).and(status.ne("Removed")))
|
||||||
|
.filter(org_id.eq(id_org)),
|
||||||
|
))
|
||||||
|
.get_result(conn)
|
||||||
|
.map_err(|e| {
|
||||||
|
anyhow!(HtyErr {
|
||||||
|
code: HtyErrCode::DbErr,
|
||||||
|
reason: Some(e.to_string()),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delete_all(conn: &mut PgConnection) -> anyhow::Result<usize> {
|
pub fn delete_all(conn: &mut PgConnection) -> anyhow::Result<usize> {
|
||||||
match diesel::delete(teacher_student::table).execute(conn) {
|
match diesel::delete(teacher_student::table).execute(conn) {
|
||||||
Ok(num) => Ok(num),
|
Ok(num) => Ok(num),
|
||||||
|
|||||||
Reference in New Issue
Block a user