use crate::ws_all::{ convert_course_sections_to_req_course_sections_for_jihua_daka_scenario, convert_course_sections_to_req_course_sections_for_jihua_daka_scenario2, find_hty_user_by_host, find_hty_user_group_by_id, }; use crate::ws_lianxi::count_lianxi_and_piyue_on_the_fly; use anyhow::anyhow; use axum::extract::{Path, Query, State}; use axum::Json; use chrono::NaiveDateTime; use diesel::PgConnection; use htycommons::common::{ current_local_datetime, get_page_and_page_size, parse_date_time, strip_result_vec, HtyErr, HtyErrCode, HtyResponse, }; use htycommons::db::{exec_read_write_task, extract_conn, fetch_db_conn, DbState}; use htycommons::jwt::jwt_decode_token; use htycommons::uuid; use htycommons::web::{ wrap_json_anyhow_err, wrap_json_ok_resp, AuthorizationHeader, HtyHostHeader, HtySudoerTokenHeader, }; use htyuc_remote::remote_calls::find_hty_user_with_info_by_id; use htyws_models::models::{ Daka, DakaCourseSection, JihuaCourseSectionMeta, Course, ReqDakaCourseSection, ReqDakaCourseSectionsRelation, ReqDakaWithCourseSectionIds, ReqDakaWithCourseSections, ReqDakaWithCourseSections2, }; use std::collections::HashMap; use std::ops::DerefMut; use std::sync::Arc; use tracing::{debug, error}; fn required_current_org_id_from_sudoer_token_str(token_str: &String) -> anyhow::Result { jwt_decode_token(token_str)? .current_org_id .ok_or_else(|| anyhow!("current_org_id is required")) } pub async fn create_daka( root: HtySudoerTokenHeader, host: HtyHostHeader, auth: AuthorizationHeader, State(db_pool): State>, Json(in_daka): Json, ) -> Json> { debug!("create_daka -> starts"); match raw_create_daka(auth, root, host, db_pool, &in_daka).await { Ok(ok) => wrap_json_ok_resp(ok), Err(e) => { error!("create_daka -> failed to create daka, e: {}", e); wrap_json_anyhow_err(e) } } } pub async fn raw_create_daka( _token: AuthorizationHeader, root: HtySudoerTokenHeader, host: HtyHostHeader, db_pool: Arc, in_req_daka: &ReqDakaWithCourseSectionIds, ) -> anyhow::Result { let current_org_id = jwt_decode_token(&(*_token).clone())? .current_org_id .ok_or_else(|| anyhow!("current_org_id is required"))?; let req_daka = in_req_daka.clone(); if req_daka.start_date.is_none() || req_daka.duration_days.is_none() || req_daka.name.is_none() || req_daka.teacher_id.is_none() // || req_daka.group_id.is_none() { return Err(anyhow!(HtyErr { code: HtyErrCode::WebErr, reason: Some( "start_date or duration_days or name or teacher_id or teacher_name is none".into() ), })); } let teacher_name = find_hty_user_by_host( &req_daka .teacher_id .clone() .ok_or_else(|| anyhow!("teacher_id is required"))?, &host, &root, ) .await? .real_name; let now = current_local_datetime(); let insert_daka = Daka { id: uuid(), desc: req_daka.desc.clone(), start_date: req_daka .start_date .clone() .ok_or_else(|| anyhow!("start_date is required"))?, duration_days: req_daka .duration_days .clone() .ok_or_else(|| anyhow!("duration_days is required"))?, name: req_daka .name .clone() .ok_or_else(|| anyhow!("name is required"))?, created_at: now.clone(), created_by: req_daka .created_by .clone() .ok_or_else(|| anyhow!("created_by is required"))?, teacher_id: req_daka .teacher_id .clone() .ok_or_else(|| anyhow!("teacher_id is required"))?, group_id: req_daka.group_id.clone(), is_delete: false, teacher_name, group_name: req_daka.group_name.clone(), lianxi_count: req_daka.lianxi_count.clone(), teachers: req_daka.teachers.clone(), updated_at: Some(now.clone()), updated_by: Some( req_daka .created_by .clone() .ok_or_else(|| anyhow!("created_by is required"))?, ), students: req_daka.students.clone(), course_sections: req_daka.course_sections.clone(), is_yanqi: req_daka.is_yanqi.clone(), org_id: Some(current_org_id), }; let mut params = HashMap::new(); params.insert("params".to_string(), (req_daka, insert_daka.clone())); let created_daka_result = raw_create_daka_tx(params, extract_conn(fetch_db_conn(&db_pool)?).deref_mut()); match created_daka_result { Ok(create_daka) => Ok(create_daka.id), Err(e) => Err(anyhow!(HtyErr { code: HtyErrCode::WebErr, reason: Some("fail to create daka e: ".to_string() + &e.to_string()), })), } } pub fn raw_create_daka_tx( params: HashMap, conn: &mut PgConnection, ) -> anyhow::Result { let task = move |in_params: Option>, conn: &mut PgConnection| -> anyhow::Result { let the_params = in_params.ok_or_else(|| anyhow!("params is required"))?; let (req_daka_with_section_ids, insert_daka) = the_params .clone() .get("params") .ok_or_else(|| anyhow!("params key not found"))? .clone(); let sections_ids = req_daka_with_section_ids .to_owned() .course_section_ids .unwrap_or_default(); debug!("START CREATE DAKA -> {:?}", &the_params); let result_daka = Daka::create(&insert_daka, conn)?; debug!("DAKA CREATED -> {:?}", &result_daka); let meta_data = JihuaCourseSectionMeta { meta: None }; for in_section_id in sections_ids { let section = DakaCourseSection { id: uuid(), daka_id: result_daka.id.clone(), course_section_id: in_section_id, meta: Some(meta_data.clone()), is_delete: false, org_id: result_daka.org_id.clone(), }; debug!("START CREATE DAKA QUMU SECTION -> {:?}", §ion); let created_section = DakaCourseSection::create(§ion, conn)?; debug!("CREATED DAKA QUMU SECTION -> {:?}", &created_section); } Ok(result_daka) }; exec_read_write_task(Box::new(task), Some(params), conn) } pub async fn find_daka_by_id( root: HtySudoerTokenHeader, Path(id): Path, State(db_pool): State>, ) -> Json> { debug!("find_daka_by_id -> start here"); match raw_find_daka_by_id(&root, &id, db_pool).await { Ok(res) => { debug!("find_daka_by_id -> successfully find daka: {:?}", res); wrap_json_ok_resp(res) } Err(e) => { error!("find_daka_by_id -> failed to find daka, e: {}", e); wrap_json_anyhow_err(e) } } } pub async fn find_daka_by_id2( root: HtySudoerTokenHeader, Path(id): Path, State(db_pool): State>, ) -> Json> { debug!("find_daka_by_id2 -> start here"); match raw_find_daka_by_id2(&root, &id, db_pool).await { Ok(res) => { debug!("find_daka_by_id2 -> successfully find daka: {:?}", res); wrap_json_ok_resp(res) } Err(e) => { error!("find_daka_by_id2 -> failed to find daka, e: {}", e); wrap_json_anyhow_err(e) } } } pub async fn raw_find_daka_by_id2( root: &HtySudoerTokenHeader, id: &String, db_pool: Arc, ) -> anyhow::Result { debug!("raw_find_daka_by_id2 -> {:?}", id); let current_org_id = required_current_org_id_from_sudoer_token_str(&root.0)?; let daka = Daka::find_by_id_in_org( &id, ¤t_org_id, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; debug!("raw_find_daka_by_id2 -> daka: {:?}", id); let all_lianxis = daka.find_active_belonging_lianxis(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?; debug!("raw_find_daka_by_id2 -> all_lianxis: {:?}", all_lianxis); let (count_lianxi, not_piyue_count) = count_lianxi_and_piyue_on_the_fly(&all_lianxis); let the_course_sections = daka.find_active_linked_course_sections(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?; debug!( "raw_find_daka_by_id2 -> the_course_sections: {:?}", the_course_sections ); let any_req_course_sections = convert_course_sections_to_req_course_sections_for_jihua_daka_scenario2( &String::from("DAKA"), &daka.id, the_course_sections.clone(), extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), ); debug!( "raw_find_daka_by_id2 -> any_req_course_sections: {:?}", any_req_course_sections ); let out_req_course_sections = strip_result_vec(any_req_course_sections)?; debug!( "raw_find_daka_by_id2 -> out_req_course_sections: {:?}", out_req_course_sections ); let any_relations: Vec> = the_course_sections .iter() .map(|course_section| { let daka_org_id = daka .org_id .as_ref() .ok_or_else(|| anyhow!("daka.org_id is required"))?; let in_jihua_course_section = DakaCourseSection::find_by_daka_id_and_course_section_id_in_org( &daka.id, &course_section.id, daka_org_id, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; Ok(ReqDakaCourseSection { id: Some(in_jihua_course_section.id.clone()), daka_id: None, course_section_id: Some(in_jihua_course_section.course_section_id.clone()), meta: None, is_delete: Some(in_jihua_course_section.is_delete.clone()), }) }) .collect(); debug!( "raw_find_daka_by_id2 -> daka.teacher_id {:?}", &daka.teacher_id ); let user_teacher = find_hty_user_with_info_by_id(&daka.teacher_id, root).await?; let user_group; if let Some(group_id) = &daka.group_id { let c_group_id = group_id.clone(); user_group = find_hty_user_group_by_id(&c_group_id.clone(), root).await?; Ok(ReqDakaWithCourseSections2 { all_lianxis: None, created_at: Some(daka.created_at.clone()), created_by: Some(daka.created_by.clone()), desc: daka.desc.clone(), duration_days: Some(daka.duration_days.clone()), group_id: Some(c_group_id.clone()), group_name: user_group.group_name, id: Some(daka.id.clone()), is_delete: Some(daka.is_delete.clone()), is_yanqi: daka.is_yanqi.clone(), lianxi_count: Some(count_lianxi), name: Some(daka.name.clone()), not_piyue_count: Some(not_piyue_count), course_sections2: daka.course_sections.clone(), course_sections: Some(out_req_course_sections), relations: Some(strip_result_vec(any_relations)?), start_date: Some(daka.start_date.clone()), students: daka.students.clone(), teacher_id: Some(daka.teacher_id.clone()), teacher_name: user_teacher.real_name, teachers: daka.teachers.clone(), updated_at: daka.updated_at.clone(), updated_by: daka.updated_by.clone(), }) } else { Ok(ReqDakaWithCourseSections2 { id: Some(daka.id.clone()), desc: daka.desc.clone(), start_date: Some(daka.start_date.clone()), duration_days: Some(daka.duration_days.clone()), name: Some(daka.name.clone()), created_at: Some(daka.created_at.clone()), created_by: Some(daka.created_by.clone()), teacher_id: Some(daka.teacher_id.clone()), group_id: None, is_delete: Some(daka.is_delete.clone()), teacher_name: user_teacher.real_name, group_name: None, course_sections: Some(out_req_course_sections), lianxi_count: Some(count_lianxi), teachers: daka.teachers.clone(), updated_at: daka.updated_at.clone(), all_lianxis: None, relations: Some(strip_result_vec(any_relations)?), not_piyue_count: Some(not_piyue_count), updated_by: daka.updated_by.clone(), students: daka.students.clone(), course_sections2: daka.course_sections.clone(), is_yanqi: daka.is_yanqi.clone(), }) } } pub async fn raw_find_daka_by_id( root: &HtySudoerTokenHeader, id: &String, db_pool: Arc, ) -> anyhow::Result { let current_org_id = required_current_org_id_from_sudoer_token_str(&root.0)?; let daka = Daka::find_by_id_in_org( &id, ¤t_org_id, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; let all_lianxis = daka.find_active_belonging_lianxis(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?; let (count_lianxi, not_piyue_count) = count_lianxi_and_piyue_on_the_fly(&all_lianxis); let the_course_sections = daka.find_active_linked_course_sections(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?; let any_req_course_sections = convert_course_sections_to_req_course_sections_for_jihua_daka_scenario( &String::from("DAKA"), &daka.id, the_course_sections.clone(), extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), ); let out_req_course_sections = strip_result_vec(any_req_course_sections)?; let any_relations: Vec> = the_course_sections .iter() .map(|course_section| { let daka_org_id = daka .org_id .as_ref() .ok_or_else(|| anyhow!("daka.org_id is required"))?; let in_jihua_course_section = DakaCourseSection::find_by_daka_id_and_course_section_id_in_org( &daka.id, &course_section.id, daka_org_id, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; Ok(ReqDakaCourseSection { id: Some(in_jihua_course_section.id.clone()), daka_id: None, course_section_id: Some(in_jihua_course_section.course_section_id.clone()), meta: None, is_delete: Some(in_jihua_course_section.is_delete.clone()), }) }) .collect(); debug!( "raw_find_daka_by_id -> daka.teacher_id {:?}", &daka.teacher_id ); let user_teacher = find_hty_user_with_info_by_id(&daka.teacher_id, root).await?; if let Some(group_id) = &daka.group_id { let c_group_id = group_id.clone(); let user_group = find_hty_user_group_by_id(&c_group_id, root).await?; Ok(ReqDakaWithCourseSections { id: Some(daka.id.clone()), desc: daka.desc.clone(), start_date: Some(daka.start_date.clone()), duration_days: Some(daka.duration_days.clone()), name: Some(daka.name.clone()), created_at: Some(daka.created_at.clone()), created_by: Some(daka.created_by.clone()), teacher_id: Some(daka.teacher_id.clone()), group_id: Some(c_group_id), is_delete: Some(daka.is_delete.clone()), teacher_name: user_teacher.real_name, group_name: user_group.group_name, course_sections: Some(out_req_course_sections), lianxi_count: Some(count_lianxi), all_lianxis: None, relations: Some(strip_result_vec(any_relations)?), not_piyue_count: Some(not_piyue_count), teachers: daka.teachers.clone(), updated_at: daka.updated_at.clone(), updated_by: daka.updated_by.clone(), students: daka.students.clone(), course_sections2: daka.course_sections.clone(), is_yanqi: daka.is_yanqi.clone(), }) } else { Ok(ReqDakaWithCourseSections { id: Some(daka.id.clone()), desc: daka.desc.clone(), start_date: Some(daka.start_date.clone()), duration_days: Some(daka.duration_days.clone()), name: Some(daka.name.clone()), created_at: Some(daka.created_at.clone()), created_by: Some(daka.created_by.clone()), teacher_id: Some(daka.teacher_id.clone()), group_id: None, is_delete: Some(daka.is_delete.clone()), teacher_name: user_teacher.real_name, group_name: None, course_sections: Some(out_req_course_sections), lianxi_count: Some(count_lianxi), all_lianxis: None, relations: Some(strip_result_vec(any_relations)?), not_piyue_count: Some(not_piyue_count), teachers: daka.teachers.clone(), updated_at: daka.updated_at.clone(), updated_by: daka.updated_by.clone(), students: daka.students.clone(), course_sections2: daka.course_sections.clone(), is_yanqi: daka.is_yanqi.clone(), }) } } pub async fn update_daka( _root: HtySudoerTokenHeader, auth: AuthorizationHeader, State(db_pool): State>, Json(in_daka): Json, ) -> Json> { debug!("update_daka_by_id -> starts"); debug!("update_daka_by_id -> in_daka / {:?}", &in_daka); match raw_update_daka(auth, db_pool, &in_daka).await { Ok(ok) => wrap_json_ok_resp(ok), Err(e) => { error!("update_jihua -> failed to update jihua, e: {}", e); wrap_json_anyhow_err(e) } } } pub async fn raw_update_daka( _token: AuthorizationHeader, db_pool: Arc, in_req_daka: &ReqDakaWithCourseSectionIds, ) -> anyhow::Result { let current_org_id = jwt_decode_token(&(*_token).clone())? .current_org_id .ok_or_else(|| anyhow!("current_org_id is required"))?; let the_req_daka = in_req_daka.clone(); let id_daka = the_req_daka .clone() .id .ok_or_else(|| anyhow!("id is required"))?; if the_req_daka.id.is_none() || the_req_daka.start_date.is_none() || the_req_daka.duration_days.is_none() || the_req_daka.name.is_none() // || the_req_daka.group_id.is_none() // || the_req_daka.teacher_id.is_none() { return Err(anyhow!(HtyErr { code: HtyErrCode::NullErr, reason: Some( "missing mandatory fields for Daka: id / start_date / duration_days / name".into() ), })); } let mut params = HashMap::new(); params.insert("c_req_daka".to_string(), the_req_daka.clone()); debug!("raw_update_daka -> update_daka -> {:?}", ¶ms); let task_update_daka = move |in_params: Option>, conn: &mut PgConnection| -> anyhow::Result<()> { let the_params = in_params.ok_or_else(|| anyhow!("params is required"))?; debug!("task_update_daka params -> {:?}", &the_params); let c_req_daka = the_params .clone() .get("c_req_daka") .ok_or_else(|| anyhow!("c_req_daka key not found"))? .clone(); let mut db_daka = Daka::find_by_id(&id_daka, conn)?; db_daka.desc = c_req_daka.desc.clone(); db_daka.start_date = c_req_daka .start_date .clone() .ok_or_else(|| anyhow!("start_date is required"))?; db_daka.duration_days = c_req_daka .duration_days .clone() .ok_or_else(|| anyhow!("duration_days is required"))?; db_daka.name = c_req_daka .name .clone() .ok_or_else(|| anyhow!("name is required"))?; db_daka.teacher_id = c_req_daka .teacher_id .clone() .ok_or_else(|| anyhow!("teacher_id is required"))?; db_daka.group_id = c_req_daka.group_id.clone(); db_daka.teacher_name = c_req_daka.teacher_name.clone(); db_daka.group_name = c_req_daka.group_name.clone(); db_daka.teachers = c_req_daka.teachers.clone(); db_daka.students = c_req_daka.students.clone(); db_daka.updated_by = c_req_daka.updated_by.clone(); db_daka.updated_at = c_req_daka.updated_at.clone(); db_daka.course_sections = c_req_daka.course_sections.clone(); db_daka.is_yanqi = c_req_daka.is_yanqi.clone(); db_daka.org_id = Some(current_org_id.clone()); debug!("raw_update_daka -> update_daka -> {:?}", &db_daka); Daka::update(&db_daka, conn)?; let _ = raw_update_daka_course_section_relations( &c_req_daka.to_req_daka_course_sections_relation()?, conn, ); Ok(()) }; let _ = match exec_read_write_task( Box::new(task_update_daka), Some(params), extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), ) { Ok(()) => Ok(()), _ => Err(anyhow!(HtyErr { code: HtyErrCode::NullErr, reason: Some("raw_update_daka -> updated error ".into()), })), }; Ok(the_req_daka .clone() .id .ok_or_else(|| anyhow!("id is required"))?) } pub fn raw_update_daka_course_section_relations( in_daka_course_sections: &ReqDakaCourseSectionsRelation, conn: &mut PgConnection, ) -> anyhow::Result<()> { debug!("in_daka_course_sections -> {:?}", in_daka_course_sections); // 先验证数据完整性 let c_in_daka_course_sections = in_daka_course_sections.clone(); let in_daka_id = c_in_daka_course_sections.daka_id.clone(); if let Some(daka_id) = &in_daka_id { let in_daka = Daka::find_by_id(daka_id, conn)?; // 确认打卡存在. debug!( "raw_update_daka_course_section_relations -> in_daka: {:?}", &in_daka ); if c_in_daka_course_sections.course_section_ids.is_none() { // *没传入关系,则不动。* debug!("raw_update_daka_course_section_relations -> no incoming `daka_course_sections` to modify"); Ok(()) } else { let in_course_section_ids = c_in_daka_course_sections .clone() .course_section_ids .clone() .ok_or_else(|| anyhow!("course_section_ids is required"))?; // 这些是传入给我们要保留/添加的关系. // *更新逻辑* // 1.把不存在于传入的`in_course_section_ids`,且已有的关系数据删掉(逻辑删除)。 // 2. `in_course_section_ids`之前没有的数据添加进表。 // 首先做第一步 // todo: 改为逻辑删除后,这里会重复查出来`已删除`关系,后续优化。 let current_org_id = in_daka .org_id .clone() .ok_or_else(|| anyhow!("daka.org_id is required"))?; let mut to_delete_relation_ids: Vec = Vec::new(); // 查找这个daka的所有course_section_ids,然后跟传入的做比对,把不存在于传入数据的ids放入`to_delete_relation_ids`,然后逻辑删除. let existing_daka_course_sections = DakaCourseSection::find_by_daka_id_in_org(daka_id, ¤t_org_id, conn)?; debug!( "raw_update_daka_course_section_relations -> existing_daka_course_sections -> {:?}", &existing_daka_course_sections ); if !existing_daka_course_sections.is_empty() { for rel in existing_daka_course_sections { let id_section = rel.course_section_id; if !in_course_section_ids.contains(&id_section) { to_delete_relation_ids.push(rel.id.clone()); // 如果这条已有关系在传入数据里不存在,则准备逻辑删除这条关系. } } } debug!( "raw_update_jihua_course_section_relations -> to_delete_relation_ids -> {:?}", &to_delete_relation_ids ); // todo: 改为逻辑删除后,这里会重复查出来`已删除`关系,后续优化。 // 删除不再需要的关系 for to_delete_rel_id in to_delete_relation_ids { // 这里只是逻辑删除. let _ = DakaCourseSection::logic_delete_by_id(&to_delete_rel_id, conn)?; } // 然后做第二步 for in_course_section_id in in_course_section_ids.clone() { match DakaCourseSection::find_by_daka_id_and_course_section_id_in_org( &in_daka.id, &in_course_section_id, ¤t_org_id, conn, ) { Ok(rel) => { debug!("find_by_daka_id_and_course_section_id -> FOUND RELATION -> {:?} / UPDATING STATUS", & rel); let mut c_rel = rel.clone(); c_rel.is_delete = false; debug!( "find_by_daka_id_and_course_section_id -> STATUS TO UPDATE {:?}", &c_rel ); let updated = DakaCourseSection::update(&c_rel, conn)?; debug!( "find_by_daka_id_and_course_section_id -> UPDATED ITEM {:?}", &updated ); } Err(_err) => { debug!( "find_by_daka_id_and_course_section_id -> NOT FOUND RELATION / ADDING" ); // 没有这条关系,添加. let to_add_rel = DakaCourseSection { id: uuid(), daka_id: daka_id.clone(), course_section_id: in_course_section_id.clone(), meta: None, is_delete: false, org_id: in_daka.org_id.clone(), }; debug!("raw_update_daka_course_section_relations -> ADDING THIS RELATION -> {:?}", & to_add_rel); let _ = DakaCourseSection::create(&to_add_rel, conn)?; } } } Ok(()) } } else { return Err(anyhow!(HtyErr { code: HtyErrCode::NullErr, reason: Some("Null Daka ID".into()), })); } } pub async fn delete_daka_by_id( root: HtySudoerTokenHeader, Path(id_delete): Path, State(db_pool): State>, ) -> Json> { debug!("delete_daka_by_id -> start here"); match raw_delete_daka_by_id(&root, &id_delete, db_pool).await { Ok(ok) => wrap_json_ok_resp(ok), Err(e) => { error!("delete_daka_by_id -> failed to delete daka, e: {}", e); wrap_json_anyhow_err(e) } } } pub async fn raw_delete_daka_by_id( root: &HtySudoerTokenHeader, id_delete: &String, db_pool: Arc, ) -> anyhow::Result<()> { let current_org_id = required_current_org_id_from_sudoer_token_str(&root.0)?; let _ = Daka::find_by_id_in_org( id_delete, ¤t_org_id, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; // 逻辑删除 daka let _ = Daka::logic_delete_by_id( id_delete, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; Ok(()) } pub async fn find_dakas_with_sections_by_user_id( Query(params): Query>, sudoer: HtySudoerTokenHeader, host: HtyHostHeader, _auth: AuthorizationHeader, State(db_pool): State>, ) -> Json, i64, i64)>> { debug!( "find_dakas_with_sections_by_user_id -> starts / params: {:?}", params ); let teacher_id = params.get("teacher_id"); let student_id = params.get("student_id"); let scope = params.get("scope"); if params.get("page").is_none() || params.get("page_size").is_none() { return wrap_json_anyhow_err(anyhow!("page or page_size not set!")); } let (some_page, some_page_size) = get_page_and_page_size(¶ms); let page = match some_page { Some(p) => p, None => return wrap_json_anyhow_err(anyhow!("page is required")), }; let page_size = match some_page_size { Some(ps) => ps, None => return wrap_json_anyhow_err(anyhow!("page_size is required")), }; if page < 1 || page_size < 1 { return wrap_json_anyhow_err(anyhow!("page or page_size not valid!")); } let start_date = params.get("start_date"); let mut start_from: Option = None; if let Some(start_date_str) = start_date { match parse_date_time(start_date_str) { Ok(dt) => start_from = Some(dt), Err(e) => return wrap_json_anyhow_err(e), } } match raw_find_dakas_with_sections_by_user_id( &teacher_id, &student_id, &scope, &start_from, page, page_size, sudoer, &host, db_pool, ) .await { Ok(ok) => wrap_json_ok_resp(ok), Err(e) => { error!( "find_dakas_with_sections_by_user_id -> failed to find, e: {}", e ); wrap_json_anyhow_err(e) } } } pub async fn raw_find_dakas_with_sections_by_user_id( teacher_id: &Option<&String>, student_id: &Option<&String>, scope: &Option<&String>, start_from: &Option, page: i64, page_size: i64, _root: HtySudoerTokenHeader, _host: &HtyHostHeader, db_pool: Arc, ) -> anyhow::Result<(Vec, i64, i64)> { debug!("raw_find_dakas_with_sections_by_user_id -> START"); debug!("raw_find_dakas_with_sections_by_user_id -> teacher_id: {:?} / student_id: {:?} / scope: {:?}", teacher_id, student_id, scope); let current_org_id = required_current_org_id_from_sudoer_token_str(&_root.0)?; if (teacher_id.is_some() && student_id.is_some()) || (teacher_id.is_none() && student_id.is_none()) { return Err(anyhow!(HtyErr { code: HtyErrCode::WebErr, reason: Some("teacher id and student id can only exits one".into()), })); } let dakas_with_pages: (Vec, i64, i64); let dakas: Vec; if teacher_id.is_some() { match scope { &Some(string_ref) => match string_ref.as_str() { "ALL" => { dakas_with_pages = Daka::find_active_dakas_by_all_teachers_with_pagination( teacher_id .as_ref() .ok_or_else(|| anyhow!("teacher_id is required"))?, ¤t_org_id, page, page_size, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; } "CREATED" => { dakas_with_pages = Daka::find_active_dakas_by_owner_teacher_with_pagination( teacher_id .as_ref() .ok_or_else(|| anyhow!("teacher_id is required"))?, ¤t_org_id, page, page_size, start_from, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; } "ASSIGNED" => { dakas_with_pages = Daka::find_active_dakas_by_assigned_teachers_with_pagination( teacher_id .as_ref() .ok_or_else(|| anyhow!("teacher_id is required"))?, ¤t_org_id, page, page_size, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; } _ => { return Err(anyhow!(HtyErr { code: HtyErrCode::WebErr, reason: Some("invalid scope".into()), })); } }, &None => { return Err(anyhow!(HtyErr { code: HtyErrCode::WebErr, reason: Some("scope can not be none when teacher_id exist".into()), })); } } dakas = dakas_with_pages.0; } else { // student_id let id_student = student_id .as_ref() .ok_or_else(|| anyhow!("student_id is required"))?; dakas_with_pages = Daka::find_active_dakas_by_student_id_with_pagination( &id_student, ¤t_org_id, page, page_size, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; dakas = dakas_with_pages.0; } let res: anyhow::Result> = dakas .iter() .map(|daka| { let mut req_daka = daka.to_req(); //--------------------------------------------------------------------------------------------------------- let linked_course_section = daka.find_active_linked_course_sections( extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; let req_course_sections: anyhow::Result> = linked_course_section .iter() .map(|course_section| { let mut req_course_section = course_section.to_req_with_ref_resource( extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; let linked_course = Course::find_by_id( course_section .course_id .as_ref() .ok_or_else(|| anyhow!("course_id is required"))?, extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; req_course_section.course_name = Some(linked_course.name); req_course_section.meta = None; Ok(req_course_section) }) .collect(); let req_course_sections = req_course_sections?; req_daka.course_sections = Some(req_course_sections); //--------------------------------------------------------------------------------------------------------- // todo: 更新数据后,切换为使用字段数据 // // req_jihua.lianxi_count = Some(count_lianxi as i32); // let c_ret_count = jihua.lianxi_count.clone(); // debug!("return lianxi_count: {:?}", c_ret_count); // if c_ret_count.is_none() { // req_jihua.lianxi_count = Some(0); // } else { // req_jihua.lianxi_count = c_ret_count; // } // fixme: 目前先动态计算 // fix: 改为使用数据库字段 // todo: 创建时练习时更新两个字段 // todo: jihua里面补充`not_piyue_count`字段 let all_lianxis = daka.find_active_belonging_lianxis( extract_conn(fetch_db_conn(&db_pool)?).deref_mut(), )?; let (count_lianxi, not_piyue_count) = count_lianxi_and_piyue_on_the_fly(&all_lianxis); req_daka.lianxi_count = Some(count_lianxi); req_daka.not_piyue_count = Some(not_piyue_count); Ok(req_daka) }) .collect(); match res { Ok(res) => Ok((res, dakas_with_pages.1, dakas_with_pages.2)), Err(e) => { debug!("err -> {:?}", e); return Err(anyhow!(e)); } } }