feat(htykc): clazz 命名迁移、消课点名与 Diesel 迁移

将课程相关表与 API 从 kecheng 迁至 clazz;新增消课/点名迁移;htyws 路由同步;工作区依赖 patch AuthCore。

Made-with: Cursor
This commit is contained in:
2026-04-24 07:43:05 +08:00
parent 1fbd3b7e29
commit bcd2c50729
17 changed files with 881 additions and 705 deletions
+786
View File
@@ -0,0 +1,786 @@
use anyhow::anyhow;
use axum::extract::{Path, Query, State};
use axum::Json;
use diesel::PgConnection;
use htycommons::common::{
current_local_datetime, get_some_from_query_params, string_to_date, string_to_datetime, HtyErr,
HtyErrCode, HtyResponse,
};
use htycommons::db::*;
use htycommons::jwt::jwt_decode_token;
use htycommons::uuid;
use htycommons::web::{
wrap_json_anyhow_err, wrap_json_ok_resp, AuthorizationHeader, HtyHostHeader,
HtySudoerTokenHeader,
};
use htykc_models::models::{
Clazz, ClazzRepeat, ReqClazz, ReqClazzRepeat, ReqClazzWithRepeat,
};
use std::collections::HashMap;
use std::ops::DerefMut;
use std::sync::Arc;
use tracing::{debug, error};
pub async fn find_all_non_repeatable_within_date_range(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Query(params): Query<HashMap<String, String>>,
) -> Json<HtyResponse<Vec<ReqClazz>>> {
debug!(
"find_all_non_repeatable_within_date_range -> starts, params: {:?}",
params
);
match raw_find_all_non_repeatable_within_date_range(
auth, sudoer, host, db_pool, &params,
) {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!(
"find_all_non_repeatable_within_date_range -> failed to find kecheng, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
fn raw_find_all_non_repeatable_within_date_range(
_token: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
params: &HashMap<String, String>,
) -> anyhow::Result<Vec<ReqClazz>> {
let start_from = string_to_date(&get_some_from_query_params::<String>("start_from", &params))?;
let end_by = string_to_date(&get_some_from_query_params::<String>("end_by", &params))?;
debug!(
"raw_find_all_non_repeatable_within_date_range -> start_from: {:?}",
start_from
);
debug!(
"raw_find_all_non_repeatable_within_date_range -> end_by: {:?}",
end_by
);
if start_from.is_none() || end_by.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("start_from or end_by is none".into()),
}));
}
let some_kechengs = Clazz::find_all_non_repeatable_by_date_range(
start_from
.as_ref()
.ok_or_else(|| anyhow!("start_from is required"))?,
end_by
.as_ref()
.ok_or_else(|| anyhow!("end_by is required"))?,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
debug!(
"raw_find_all_non_repeatable_within_date_range -> some_kechengs: {:?}",
some_kechengs
);
if let Some(kechengs) = some_kechengs {
let res: Vec<ReqClazz> = kechengs.iter().map(|kc| kc.to_req()).collect();
Ok(res)
} else {
Ok(vec![])
}
}
pub async fn find_all_non_repeatable_within_date_range_by_hty_id(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Query(params): Query<HashMap<String, String>>,
) -> Json<HtyResponse<Vec<ReqClazz>>> {
debug!(
"find_all_non_repeatable_within_date_range_by_hty_id -> starts, params: {:?}",
params
);
match raw_find_all_non_repeatable_within_date_range_by_hty_id(
auth, sudoer, host, db_pool, &params,
) {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!(
"find_all_non_repeatable_within_date_range_by_hty_id -> failed to find kecheng, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
fn raw_find_all_non_repeatable_within_date_range_by_hty_id(
_token: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
params: &HashMap<String, String>,
) -> anyhow::Result<Vec<ReqClazz>> {
let start_from =
string_to_datetime(&get_some_from_query_params::<String>("start_from", &params))?;
let end_by = string_to_datetime(&get_some_from_query_params::<String>("end_by", &params))?;
debug!(
"raw_find_all_non_repeatable_within_date_range_by_hty_id -> start_from: {:?}",
start_from
);
debug!(
"raw_find_all_non_repeatable_within_date_range_by_hty_id -> end_by: {:?}",
end_by
);
let id_user = get_some_from_query_params::<String>("hty_id", &params);
if start_from.is_none() || end_by.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("start_from or end_by is none".into()),
}));
}
if id_user.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("hty_id is none".into()),
}));
}
let some_kechengs = Clazz::find_all_non_repeatable_by_date_range_and_user_id(
id_user
.as_ref()
.ok_or_else(|| anyhow!("id_user is required"))?,
start_from
.as_ref()
.ok_or_else(|| anyhow!("start_from is required"))?,
end_by
.as_ref()
.ok_or_else(|| anyhow!("end_by is required"))?,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
debug!(
"raw_find_all_non_repeatable_within_date_range_by_hty_id -> {:?}",
some_kechengs
);
if let Some(kechengs) = some_kechengs {
let res: Vec<ReqClazz> = kechengs.iter().map(|kc| kc.to_req()).collect();
Ok(res)
} else {
Ok(vec![])
}
}
pub async fn find_all_repeatable_within_date_range(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Query(params): Query<HashMap<String, String>>,
) -> Json<HtyResponse<Vec<ReqClazzWithRepeat>>> {
debug!(
"find_all_repeatable_within_date_range -> starts, params: {:?}",
params
);
match raw_find_all_repeatable_within_date_range(auth, sudoer, host, db_pool, &params) {
Ok(kechengs) => wrap_json_ok_resp(kechengs),
Err(e) => {
error!(
"find_all_repeatable_within_date_range -> failed to find kecheng, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
fn raw_find_all_repeatable_within_date_range(
_token: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
params: &HashMap<String, String>,
) -> anyhow::Result<Vec<ReqClazzWithRepeat>> {
let start_from = string_to_date(&get_some_from_query_params::<String>("start_from", &params))?;
let end_by = string_to_date(&get_some_from_query_params::<String>("end_by", &params))?;
debug!(
"raw_find_all_repeatable_within_date_range -> start_from: {:?}",
start_from
);
debug!(
"raw_find_all_repeatable_within_date_range -> end_by: {:?}",
end_by
);
if start_from.is_none() || end_by.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("start_from or end_by is none".into()),
}));
}
let some_kechengs = Clazz::find_all_repeatable_by_date_range(
start_from
.as_ref()
.ok_or_else(|| anyhow!("start_from is required"))?,
end_by
.as_ref()
.ok_or_else(|| anyhow!("end_by is required"))?,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
debug!(
"raw_find_all_repeatable_within_date_range -> some_kechengs: {:?}",
some_kechengs
);
if let Some(kechengs) = some_kechengs {
debug!(
"raw_find_all_repeatable_within_date_range -> kechengs.len(): {:?}",
kechengs.len()
);
Ok(kechengs)
} else {
Ok(vec![])
}
}
pub async fn find_all_repeatable_within_date_range_by_hty_id(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Query(params): Query<HashMap<String, String>>,
) -> Json<HtyResponse<Vec<ReqClazzWithRepeat>>> {
debug!(
"find_all_repeatable_within_date_range_by_hty_id -> starts, params: {:?}",
params
);
match raw_find_all_repeatable_within_date_range_by_hty_id(
auth, sudoer, host, db_pool, &params,
) {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!(
"find_all_repeatable_within_date_range_by_hty_id -> failed to find kecheng, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
/*
* 找到前端给定时间范围内的所有kecheng数据
* 本周的重复课程如果存在,返回重复课程对应的sudoer课程
* 1. hty_user_id / 哪个用的课程
* 2. start_from / end_by
* 3. 实体kecheng数据
* 4. 需要显示在本周的重复课程的sudoer课程 (kecheng_repeat_status == `OPEN` && is_repeat == True && repeat_end 在本周范围内 or 为空)
* htykc_moicen=# select kecheng.is_repeat from kecheng join kecheng_repeat on kecheng.id = kecheng_repeat.clazz_id where kecheng.is_repeat is not null;
*
* a. 返回的kecheng里,如果`id == root_id`那么此条数据就是sudoer数据.
* b. 如果此条kecheng的`start_from`和`end_by`落在本周,则说明是本周数据
*/
fn raw_find_all_repeatable_within_date_range_by_hty_id(
_token: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
params: &HashMap<String, String>,
) -> anyhow::Result<Vec<ReqClazzWithRepeat>> {
let start_from =
string_to_datetime(&get_some_from_query_params::<String>("start_from", &params))?;
let end_by = string_to_datetime(&get_some_from_query_params::<String>("end_by", &params))?;
debug!(
"raw_find_all_repeatable_within_date_range_by_hty_id -> start_from: {:?}",
start_from
);
debug!(
"raw_find_all_repeatable_within_date_range_by_hty_id -> end_by: {:?}",
end_by
);
let id_user = get_some_from_query_params::<String>("hty_id", &params);
if start_from.is_none() || end_by.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("start_from or end_by is none".into()),
}));
}
if id_user.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("hty_id is none".into()),
}));
}
let some_kechengs = Clazz::find_all_repeatable_by_date_range_and_user_id(
id_user
.as_ref()
.ok_or_else(|| anyhow!("id_user is required"))?,
start_from
.as_ref()
.ok_or_else(|| anyhow!("start_from is required"))?,
end_by
.as_ref()
.ok_or_else(|| anyhow!("end_by is required"))?,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
debug!(
"raw_find_all_repeatable_within_date_range_by_hty_id -> some_kechengs: {:?}",
some_kechengs
);
if let Some(kechengs) = some_kechengs {
debug!(
"raw_find_all_repeatable_within_date_range_by_hty_id -> kechengs.len(): {:?}",
kechengs.len()
);
Ok(kechengs)
} else {
Ok(vec![])
}
}
pub async fn find_by_daka_ids(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
daka_ids: Json<Vec<String>>,
) -> Json<HtyResponse<Vec<ReqClazz>>> {
debug!("find_by_daka_ids -> starts: {:?}", daka_ids);
match raw_find_by_daka_ids(auth, sudoer, host, db_pool, &daka_ids) {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!(
"find_by_daka_ids -> failed to find kecheng, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
fn raw_find_by_daka_ids(
_auth: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
daka_ids: &Vec<String>,
) -> anyhow::Result<Vec<ReqClazz>> {
let db_kechengs = Clazz::find_by_daka_ids(
daka_ids,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
debug!(
"raw_find_by_daka_ids -> db_kechengs: {:?}",
db_kechengs
);
let req_kechengs = db_kechengs.into_iter().map(|item| item.to_req()).collect();
debug!(
"raw_find_by_daka_ids -> req_kechengs: {:?}",
req_kechengs
);
Ok(req_kechengs)
}
pub async fn find_clazz_repeat_by_id(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Path(id): Path<String>,
) -> Json<HtyResponse<ReqClazzRepeat>> {
debug!("find_clazz_repeat_by_id -> starts: {:?}", id);
match raw_find_clazz_repeat_by_id(auth, sudoer, host, db_pool, &id) {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!(
"find_clazz_repeat_by_id -> failed to find kecheng repeat, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
fn raw_find_clazz_repeat_by_id(
_auth: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
kecheng_repeat_id: &String,
) -> anyhow::Result<ReqClazzRepeat> {
let res = ClazzRepeat::find_by_id(
kecheng_repeat_id,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
if let Some(kecheng_repeat) = res {
return Ok(kecheng_repeat.to_req());
} else {
return Err(anyhow!(HtyErr {
code: HtyErrCode::NullErr,
reason: Some(format!(
"raw_find_clazz_repeat_by_id -> failed to find record according to id :{:?}.",
kecheng_repeat_id
)),
}));
}
}
pub async fn find_clazz_by_hty_id(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Query(params): Query<HashMap<String, String>>,
) -> Json<HtyResponse<Vec<ReqClazz>>> {
debug!("find_clazz_by_hty_id -> starts: {:?}", params);
match raw_find_clazz_by_hty_id(auth, sudoer, host, db_pool, &params) {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!(
"find_clazz_by_hty_id -> failed to find kechengs, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
fn raw_find_clazz_by_hty_id(
_auth: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
params: &HashMap<String, String>,
) -> anyhow::Result<Vec<ReqClazz>> {
let start_date =
string_to_datetime(&get_some_from_query_params::<String>("start_date", &params))?;
let end_date = string_to_datetime(&get_some_from_query_params::<String>("end_date", &params))?;
debug!(
"raw_find_clazz_by_hty_id -> start_date: {:?}",
start_date
);
debug!("raw_find_clazz_by_hty_id -> end_date: {:?}", end_date);
if start_date.is_none() || end_date.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("start_date or end_date is none".into()),
}));
}
let id_user = get_some_from_query_params::<String>("hty_id", &params);
if id_user.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("hty_id is none".into()),
}));
}
let kechengs = Clazz::find_by_user_id(
id_user
.as_ref()
.ok_or_else(|| anyhow!("id_user is required"))?,
&start_date,
&end_date,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
let res = kechengs.into_iter().map(|item| item.to_req()).collect();
debug!("raw_find_clazz_by_hty_id -> {:?}", res);
Ok(res)
}
pub async fn update_clazz(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Json(in_kecheng): Json<ReqClazz>,
) -> Json<HtyResponse<()>> {
debug!("update_clazz -> in_kecheng: {:?}", in_kecheng);
match raw_update_clazz(auth, sudoer, host, db_pool, &in_kecheng).await {
Ok(ok) => wrap_json_ok_resp(ok),
Err(e) => {
error!("update_clazz -> failed to update clazz, e: {}", e);
wrap_json_anyhow_err(e)
}
}
}
async fn raw_update_clazz(
_token: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
in_kecheng: &ReqClazz,
) -> anyhow::Result<()> {
if in_kecheng.id.is_none() {
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("clazz_id is none".into()),
}));
}
let id_kecheng = in_kecheng
.id
.clone()
.ok_or_else(|| anyhow!("id is required"))?;
let mut db_kecheng = Clazz::find_by_id(
&id_kecheng,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
if let Some(clazz_name) = &in_kecheng.clazz_name {
db_kecheng.clazz_name = clazz_name.clone();
}
if let Some(clazz_status) = &in_kecheng.clazz_status {
db_kecheng.clazz_status = clazz_status.clone();
}
if let Some(start_from) = &in_kecheng.start_from {
db_kecheng.start_from = start_from.clone();
}
if let Some(end_by) = &in_kecheng.end_by {
db_kecheng.end_by = end_by.clone();
}
if let Some(root_id) = &in_kecheng.root_id {
db_kecheng.root_id = root_id.clone();
}
if let Some(parent_id) = &in_kecheng.parent_id {
db_kecheng.parent_id = parent_id.clone();
}
db_kecheng.clazz_desc = in_kecheng.clazz_desc.clone();
db_kecheng.duration = in_kecheng.duration.clone();
db_kecheng.clazz_type = in_kecheng.clazz_type.clone();
db_kecheng.students = in_kecheng.students.clone();
db_kecheng.teachers = in_kecheng.teachers.clone();
db_kecheng.jihuas = in_kecheng.jihuas.clone();
db_kecheng.dakas = in_kecheng.dakas.clone();
db_kecheng.is_delete = in_kecheng.is_delete.clone();
db_kecheng.is_repeat = in_kecheng.is_repeat.clone();
db_kecheng.course_sections = in_kecheng.course_sections.clone();
db_kecheng.is_notified = in_kecheng.is_notified.clone();
debug!("raw_update_clazz -> {:?}", db_kecheng);
let _ = Clazz::update(
&db_kecheng,
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)?;
Ok(())
}
/*async fn find_group_users_by_group_id(_p0: &String, _p1: &HtyHostHeader, _p2: &HtySudoerTokenHeader) -> anyhow::Result<Option<Vec<ReqClazzUser>>> {
unimplemented!()
}
*/
fn raw_create_clazz_with_repeat_tx(
params: HashMap<String, (Clazz, Option<ClazzRepeat>)>,
db_pool: Arc<DbState>,
) -> anyhow::Result<ReqClazz> {
let task = move |in_params: Option<HashMap<String, (Clazz, Option<ClazzRepeat>)>>,
conn: &mut PgConnection|
-> anyhow::Result<ReqClazz> {
let the_params = in_params.ok_or_else(|| anyhow!("params is required"))?;
let (to_create_kecheng, to_create_kecheng_repeat) = the_params
.clone()
.get("params")
.ok_or_else(|| anyhow!("params key not found"))?
.clone();
let created_kecheng = Clazz::create(&to_create_kecheng, conn)?;
debug!(
"raw_create_clazz_with_repeat_tx -> created_kecheng: {:?}",
created_kecheng
);
let mut created_kecheng_repeat = None;
if let Some(kecheng_repeat) = &to_create_kecheng_repeat {
created_kecheng_repeat = Some(ClazzRepeat::create(kecheng_repeat, conn)?);
debug!(
"raw_create_clazz_with_repeat_tx -> created_kecheng_repeat: {:?}",
created_kecheng_repeat
);
}
let out =
ReqClazz::from_clazz_and_repeat(&Some(created_kecheng), &created_kecheng_repeat);
debug!("raw_create_clazz_with_repeat_tx -> out: {:?}", out);
Ok(out)
};
exec_read_write_task(
Box::new(task),
Some(params),
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
)
}
pub async fn create_clazz_with_repeat(
sudoer: HtySudoerTokenHeader,
host: HtyHostHeader,
auth: AuthorizationHeader,
State(db_pool): State<Arc<DbState>>,
Json(in_kecheng): Json<ReqClazz>,
) -> Json<HtyResponse<ReqClazz>> {
debug!(
"create_clazz_with_repeat -> in_kecheng: {:?}",
in_kecheng
);
match raw_create_clazz_with_repeat(auth, sudoer, host, db_pool, &in_kecheng).await {
Ok(out) => wrap_json_ok_resp(out),
Err(e) => {
error!(
"create_clazz_with_repeat -> failed to create clazz, e: {}",
e
);
wrap_json_anyhow_err(e)
}
}
}
async fn raw_create_clazz_with_repeat(
token: AuthorizationHeader,
_sudoer: HtySudoerTokenHeader,
_host: HtyHostHeader,
db_pool: Arc<DbState>,
in_kecheng: &ReqClazz,
) -> anyhow::Result<ReqClazz> {
if in_kecheng.clazz_name.is_none()
|| in_kecheng.start_from.is_none()
|| in_kecheng.end_by.is_none()
|| in_kecheng.duration.is_none()
{
return Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some(
"clazz_name or start_from or end_by or duration or users is none".into(),
),
}));
}
let id_user = jwt_decode_token(&(*token).clone())?
.hty_id
.ok_or_else(|| anyhow!("hty_id is required"))?;
debug!(
"raw_create_clazz_with_repeat -> id_user: {:?}",
id_user
);
let new_clazz_id = uuid();
let id_sudoer = in_kecheng
.root_id
.clone()
.unwrap_or_else(|| new_clazz_id.clone());
let id_parent = in_kecheng
.parent_id
.clone()
.unwrap_or_else(|| new_clazz_id.clone());
let to_create_kecheng = Clazz {
id: new_clazz_id.clone(),
clazz_name: in_kecheng
.clazz_name
.clone()
.ok_or_else(|| anyhow!("clazz_name is required"))?,
clazz_status: in_kecheng
.clazz_status
.clone()
.ok_or_else(|| anyhow!("clazz_status is required"))?,
clazz_desc: in_kecheng.clazz_desc.clone(),
start_from: in_kecheng
.start_from
.clone()
.ok_or_else(|| anyhow!("start_from is required"))?,
end_by: in_kecheng
.end_by
.clone()
.ok_or_else(|| anyhow!("end_by is required"))?,
duration: in_kecheng.duration.clone(),
root_id: id_sudoer.clone(),
clazz_type: in_kecheng.clazz_type.clone(),
parent_id: id_parent.clone(),
created_by: in_kecheng.created_by.clone(),
created_at: Some(current_local_datetime()),
students: in_kecheng.students.clone(),
teachers: in_kecheng.teachers.clone(),
jihuas: in_kecheng.jihuas.clone(),
dakas: in_kecheng.dakas.clone(),
is_delete: in_kecheng.is_delete.clone(),
is_repeat: in_kecheng.is_repeat.clone(),
course_sections: in_kecheng.course_sections.clone(),
is_notified: in_kecheng.is_notified.clone(),
};
debug!(
"raw_create_clazz_with_repeat -> to_create_kecheng: {:?}",
to_create_kecheng
);
let mut to_create_kecheng_repeat: Option<ClazzRepeat> = None;
if let Some(kecheng_repeat) = &in_kecheng.clazz_repeat {
let kecheng_repeat_copy = kecheng_repeat.clone();
to_create_kecheng_repeat = Some(ClazzRepeat {
id: uuid(),
clazz_id: Some(new_clazz_id.clone()),
start_from: kecheng_repeat_copy.start_from.clone(),
end_by: kecheng_repeat_copy.end_by.clone(),
repeat_start: kecheng_repeat_copy.repeat_start.clone(),
repeat_cycle_days: kecheng_repeat_copy.repeat_cycle_days.clone(),
repeat_end: kecheng_repeat_copy.repeat_end.clone(),
repeat_status: kecheng_repeat_copy.repeat_status.clone(),
latest_clazz_created_at: kecheng_repeat_copy.latest_clazz_created_at.clone(),
})
}
let mut params = HashMap::new();
params.insert(
"params".to_string(),
(to_create_kecheng, to_create_kecheng_repeat),
);
let out_result = raw_create_clazz_with_repeat_tx(params, db_pool);
match out_result {
Ok(out) => {
debug!("created_kecheng: {:?}", out);
Ok(out)
}
Err(e) => Err(anyhow!(HtyErr {
code: HtyErrCode::WebErr,
reason: Some("fail to create clazz e: ".to_string() + &e.to_string()),
})),
}
}