fix(ws-org): enforce org-scoped lianxi relation lookups
Require current_org_id for lianxi deletion and relation traversal, and add org-scoped relation lookups to prevent cross-organization hits in daka/jihua counters. Made-with: Cursor
This commit is contained in:
+59
-15
@@ -112,24 +112,40 @@ pub async fn raw_create_lianxi(
|
||||
|
||||
debug!("update lianxi_count");
|
||||
if let Some(section_id) = &in_jihua_course_section_id {
|
||||
let jihua_course_section = JihuaCourseSection::find_by_id(
|
||||
let jihua_course_section = JihuaCourseSection::find_by_id_in_org(
|
||||
section_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let belonging_jihua = Jihua::find_by_id(
|
||||
let belonging_jihua = Jihua::find_by_id_in_org(
|
||||
&jihua_course_section.jihua_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let _ = belonging_jihua
|
||||
.update_count(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
||||
} else if let Some(section_id) = &in_daka_course_section_id {
|
||||
// in_daka_course_section_id is some
|
||||
let daka_course_section = DakaCourseSection::find_by_id(
|
||||
let daka_course_section = DakaCourseSection::find_by_id_in_org(
|
||||
section_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let belonging_daka = Daka::find_by_id(
|
||||
let belonging_daka = Daka::find_by_id_in_org(
|
||||
&daka_course_section.daka_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let _ = belonging_daka
|
||||
@@ -306,24 +322,40 @@ pub async fn raw_create_lianxi2(
|
||||
|
||||
debug!("update lianxi_count");
|
||||
if let Some(section_id) = &in_jihua_course_section_id {
|
||||
let jihua_course_section = JihuaCourseSection::find_by_id(
|
||||
let jihua_course_section = JihuaCourseSection::find_by_id_in_org(
|
||||
section_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let belonging_jihua = Jihua::find_by_id(
|
||||
let belonging_jihua = Jihua::find_by_id_in_org(
|
||||
&jihua_course_section.jihua_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let _ = belonging_jihua
|
||||
.update_count(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
||||
} else if let Some(section_id) = &in_daka_course_section_id {
|
||||
// in_daka_course_section_id is some
|
||||
let daka_course_section = DakaCourseSection::find_by_id(
|
||||
let daka_course_section = DakaCourseSection::find_by_id_in_org(
|
||||
section_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let belonging_daka = Daka::find_by_id(
|
||||
let belonging_daka = Daka::find_by_id_in_org(
|
||||
&daka_course_section.daka_id,
|
||||
&res_lianxi
|
||||
.org_id
|
||||
.clone()
|
||||
.ok_or_else(|| anyhow!("lianxi.org_id is required"))?,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let _ = belonging_daka
|
||||
@@ -340,12 +372,12 @@ pub async fn raw_create_lianxi2(
|
||||
}
|
||||
|
||||
pub async fn delete_lianxi_by_id(
|
||||
_root: HtySudoerTokenHeader,
|
||||
root: HtySudoerTokenHeader,
|
||||
Path(id_delete): Path<String>,
|
||||
State(db_pool): State<Arc<DbState>>,
|
||||
) -> Json<HtyResponse<Lianxi>> {
|
||||
debug!("delete_lianxi_by_id -> start here");
|
||||
match raw_delete_lianxi_by_id(&id_delete, db_pool).await {
|
||||
match raw_delete_lianxi_by_id(&root, &id_delete, db_pool).await {
|
||||
Ok(ok) => wrap_json_ok_resp(ok),
|
||||
Err(e) => {
|
||||
error!("delete_lianxi_by_id -> failed to delete lianxi, e: {}", e);
|
||||
@@ -355,11 +387,14 @@ pub async fn delete_lianxi_by_id(
|
||||
}
|
||||
|
||||
pub async fn raw_delete_lianxi_by_id(
|
||||
root: &HtySudoerTokenHeader,
|
||||
id_delete: &String,
|
||||
db_pool: Arc<DbState>,
|
||||
) -> anyhow::Result<Lianxi> {
|
||||
let to_delete_lianxi = Lianxi::find_by_id(
|
||||
let current_org_id = required_current_org_id_from_sudoer_token_str(&root.0)?;
|
||||
let to_delete_lianxi = Lianxi::find_by_id_in_org(
|
||||
id_delete,
|
||||
¤t_org_id,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let piyues =
|
||||
@@ -390,12 +425,14 @@ pub async fn raw_delete_lianxi_by_id(
|
||||
}
|
||||
|
||||
if let Some(section_id) = &to_delete_lianxi.jihua_course_section_id {
|
||||
let relation = JihuaCourseSection::find_by_id(
|
||||
let relation = JihuaCourseSection::find_by_id_in_org(
|
||||
section_id,
|
||||
¤t_org_id,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let belonging_jihua = Jihua::find_by_id(
|
||||
let belonging_jihua = Jihua::find_by_id_in_org(
|
||||
&relation.jihua_id,
|
||||
¤t_org_id,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let _ = belonging_jihua.update_count(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
||||
@@ -406,12 +443,12 @@ pub async fn raw_delete_lianxi_by_id(
|
||||
}
|
||||
|
||||
pub async fn delete_lianxi_by_id2(
|
||||
_root: HtySudoerTokenHeader,
|
||||
root: HtySudoerTokenHeader,
|
||||
Path(id_delete): Path<String>,
|
||||
State(db_pool): State<Arc<DbState>>,
|
||||
) -> Json<HtyResponse<ReqLianxi2>> {
|
||||
debug!("delete_lianxi_by_id2 -> start here");
|
||||
match raw_delete_lianxi_by_id2(&id_delete, db_pool).await {
|
||||
match raw_delete_lianxi_by_id2(&root, &id_delete, db_pool).await {
|
||||
Ok(ok) => wrap_json_ok_resp(ok),
|
||||
Err(e) => {
|
||||
error!("delete_lianxi_by_id2 -> failed to delete lianxi, e: {}", e);
|
||||
@@ -421,11 +458,18 @@ pub async fn delete_lianxi_by_id2(
|
||||
}
|
||||
|
||||
pub async fn raw_delete_lianxi_by_id2(
|
||||
root: &HtySudoerTokenHeader,
|
||||
id_delete: &String,
|
||||
db_pool: Arc<DbState>,
|
||||
) -> anyhow::Result<ReqLianxi2> {
|
||||
// let to_delete_lianxi = Lianxi::find_by_id(id_delete, extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
||||
// let piyues = to_delete_lianxi.find_linked_piyues(extract_conn(fetch_db_conn(&db_pool)?).deref_mut())?;
|
||||
let current_org_id = required_current_org_id_from_sudoer_token_str(&root.0)?;
|
||||
let _ = Lianxi::find_by_id_in_org(
|
||||
id_delete,
|
||||
¤t_org_id,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
)?;
|
||||
let deleted_lianxi = Lianxi::logic_delete_by_id(
|
||||
id_delete,
|
||||
extract_conn(fetch_db_conn(&db_pool)?).deref_mut(),
|
||||
|
||||
@@ -2150,6 +2150,24 @@ impl JihuaCourseSection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_by_id_in_org(
|
||||
id_search: &String,
|
||||
id_org: &String,
|
||||
conn: &mut PgConnection,
|
||||
) -> anyhow::Result<JihuaCourseSection> {
|
||||
use crate::schema::jihua_course_section::columns::*;
|
||||
use crate::schema::jihua_course_section::dsl::*;
|
||||
jihua_course_section
|
||||
.filter(id.eq(id_search).and(org_id.eq(id_org)))
|
||||
.first::<JihuaCourseSection>(conn)
|
||||
.map_err(|e| {
|
||||
anyhow!(HtyErr {
|
||||
code: HtyErrCode::DbErr,
|
||||
reason: Some(e.to_string()),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_first_by_course_section_id(
|
||||
id_course_section: &String,
|
||||
conn: &mut PgConnection,
|
||||
@@ -3833,6 +3851,24 @@ impl DakaCourseSection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_by_id_in_org(
|
||||
id_search: &String,
|
||||
id_org: &String,
|
||||
conn: &mut PgConnection,
|
||||
) -> anyhow::Result<DakaCourseSection> {
|
||||
use crate::schema::daka_course_section::columns::*;
|
||||
use crate::schema::daka_course_section::dsl::*;
|
||||
daka_course_section
|
||||
.filter(id.eq(id_search).and(org_id.eq(id_org)))
|
||||
.first::<DakaCourseSection>(conn)
|
||||
.map_err(|e| {
|
||||
anyhow!(HtyErr {
|
||||
code: HtyErrCode::DbErr,
|
||||
reason: Some(e.to_string()),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn find_by_daka_id_and_course_section_id(
|
||||
id_daka: &String,
|
||||
id_course_section: &String,
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
-- htyws 多租户 org_id 历史数据回填(仅回填 NULL)
|
||||
-- 使用方式(moicen):
|
||||
-- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f /path/to/tmp_htyws_org_backfill.sql
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 1) 先从已确定来源回填关系链:
|
||||
-- jihua_course_section <- jihua
|
||||
UPDATE jihua_course_section jcs
|
||||
SET org_id = j.org_id
|
||||
FROM jihua j
|
||||
WHERE jcs.jihua_id = j.id
|
||||
AND jcs.org_id IS NULL
|
||||
AND j.org_id IS NOT NULL;
|
||||
|
||||
-- daka_course_section <- daka
|
||||
UPDATE daka_course_section dcs
|
||||
SET org_id = d.org_id
|
||||
FROM daka d
|
||||
WHERE dcs.daka_id = d.id
|
||||
AND dcs.org_id IS NULL
|
||||
AND d.org_id IS NOT NULL;
|
||||
|
||||
-- 2) 回填 lianxi.org_id(优先 jihua,再 daka)
|
||||
UPDATE lianxi l
|
||||
SET org_id = jcs.org_id
|
||||
FROM jihua_course_section jcs
|
||||
WHERE l.jihua_course_section_id = jcs.id
|
||||
AND l.org_id IS NULL
|
||||
AND jcs.org_id IS NOT NULL;
|
||||
|
||||
UPDATE lianxi l
|
||||
SET org_id = dcs.org_id
|
||||
FROM daka_course_section dcs
|
||||
WHERE l.daka_course_section_id = dcs.id
|
||||
AND l.org_id IS NULL
|
||||
AND dcs.org_id IS NOT NULL;
|
||||
|
||||
-- 3) 回填 piyue / piyue_info
|
||||
UPDATE piyue p
|
||||
SET org_id = l.org_id
|
||||
FROM lianxi l
|
||||
WHERE p.lianxi_id = l.id
|
||||
AND p.org_id IS NULL
|
||||
AND l.org_id IS NOT NULL;
|
||||
|
||||
UPDATE piyue_info pi
|
||||
SET org_id = p.org_id
|
||||
FROM piyue p
|
||||
WHERE pi.piyue_id = p.id
|
||||
AND pi.org_id IS NULL
|
||||
AND p.org_id IS NOT NULL;
|
||||
|
||||
-- 4) 回填 course_section.org_id
|
||||
-- 4.1 course_section <- jihua_course_section
|
||||
UPDATE course_section cs
|
||||
SET org_id = jcs.org_id
|
||||
FROM jihua_course_section jcs
|
||||
WHERE jcs.course_section_id = cs.id
|
||||
AND cs.org_id IS NULL
|
||||
AND jcs.org_id IS NOT NULL;
|
||||
|
||||
-- 4.2 course_section <- daka_course_section
|
||||
UPDATE course_section cs
|
||||
SET org_id = dcs.org_id
|
||||
FROM daka_course_section dcs
|
||||
WHERE dcs.course_section_id = cs.id
|
||||
AND cs.org_id IS NULL
|
||||
AND dcs.org_id IS NOT NULL;
|
||||
|
||||
-- 4.3 course_section <- course
|
||||
UPDATE course_section cs
|
||||
SET org_id = c.org_id
|
||||
FROM course c
|
||||
WHERE cs.course_id = c.id
|
||||
AND cs.org_id IS NULL
|
||||
AND c.org_id IS NOT NULL;
|
||||
|
||||
-- 5) 回填 course.org_id(来自已回填完的 section)
|
||||
WITH section_org AS (
|
||||
SELECT cs.course_id, MIN(cs.org_id) AS resolved_org_id
|
||||
FROM course_section cs
|
||||
WHERE cs.course_id IS NOT NULL
|
||||
AND cs.org_id IS NOT NULL
|
||||
GROUP BY cs.course_id
|
||||
)
|
||||
UPDATE course c
|
||||
SET org_id = so.resolved_org_id
|
||||
FROM section_org so
|
||||
WHERE c.id = so.course_id
|
||||
AND c.org_id IS NULL;
|
||||
|
||||
-- 6) 回填 jihua / daka(来自其关系表)
|
||||
WITH jihua_rel_org AS (
|
||||
SELECT jcs.jihua_id, MIN(jcs.org_id) AS resolved_org_id
|
||||
FROM jihua_course_section jcs
|
||||
WHERE jcs.org_id IS NOT NULL
|
||||
GROUP BY jcs.jihua_id
|
||||
)
|
||||
UPDATE jihua j
|
||||
SET org_id = jro.resolved_org_id
|
||||
FROM jihua_rel_org jro
|
||||
WHERE j.id = jro.jihua_id
|
||||
AND j.org_id IS NULL;
|
||||
|
||||
WITH daka_rel_org AS (
|
||||
SELECT dcs.daka_id, MIN(dcs.org_id) AS resolved_org_id
|
||||
FROM daka_course_section dcs
|
||||
WHERE dcs.org_id IS NOT NULL
|
||||
GROUP BY dcs.daka_id
|
||||
)
|
||||
UPDATE daka d
|
||||
SET org_id = dro.resolved_org_id
|
||||
FROM daka_rel_org dro
|
||||
WHERE d.id = dro.daka_id
|
||||
AND d.org_id IS NULL;
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 回填后建议检查:
|
||||
-- SELECT 'course' tbl, count(*) FROM course WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'course_section', count(*) FROM course_section WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'lianxi', count(*) FROM lianxi WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'piyue', count(*) FROM piyue WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'piyue_info', count(*) FROM piyue_info WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'jihua', count(*) FROM jihua WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'daka', count(*) FROM daka WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'jihua_course_section', count(*) FROM jihua_course_section WHERE org_id IS NULL
|
||||
-- UNION ALL SELECT 'daka_course_section', count(*) FROM daka_course_section WHERE org_id IS NULL;
|
||||
Reference in New Issue
Block a user