Skip to content

修正操作紀錄「資源」連結對提案一律 404,並補上別名分頁的出處/頁碼/備註欄 - #1283

Merged
sudoghut merged 2 commits into
cbdb-project:developfrom
frankslin:fix/proposal-resource-link-404
Aug 26, 2026
Merged

修正操作紀錄「資源」連結對提案一律 404,並補上別名分頁的出處/頁碼/備註欄#1283
sudoghut merged 2 commits into
cbdb-project:developfrom
frankslin:fix/proposal-resource-link-404

Conversation

@frankslin

Copy link
Copy Markdown
Contributor

起因

回報:/app/operations?proposals_only=1 裡明明有這筆別名提案,但點「資源」連結直接 404 ——

/app/basicinformation/85303/altnames/edit-v2?c_personid=85303&c_alt_name_chn=雪䕬&c_alt_name_type_code=5

排查後發現是兩件互相獨立的事,各一個 commit。

1. 修正操作紀錄「資源」連結對提案一律 404

operations.resource_id 存的是提案完成後的主鍵,是先於現實寫進去的:

  • create 提案:核准前那一列根本不存在;
  • update 提案:只要改到任一主鍵成員就是尚不存在的新鍵——不只 ALTNAME_DATA.c_alt_name_chnASSOC_DATA.c_text_titleBIOG_SOURCE_DATA.c_pages 這三個文本型,BIOG_ADDR_DATA.c_addr_typeKIN_DATA.c_kin_codeBIOG_TEXT_DATA.c_role_id 這些代碼型主鍵成員也都在各自 handler 的 allowedFields() 裡;
  • delete 提案:核准後舊鍵那一列已被刪除。

OperationsController::serializeOperationRow() 的守衛原本只擋 op_type = 4,於是提案列照樣產出連結,而 appAltnameEditV2() 之流以主鍵查不到列就 abort(404)這是全部 12 張複合主鍵人物子資源共通的缺口,不限別名。

修法是新增 resolveLinkResourceId(),把「連結該指向哪一列」與「這筆操作記錄的是什麼」分開:

op_type 未核准 已核准
8 提案新增 不出連結 resource_id(已指向實際建立的列)
9 提案修改 改用 resource_original 的主鍵 resource_id(新鍵即現況)
10 提案刪除 resource_id(列還在) 不出連結

未核准的 update 改以 original 定位,與核准路徑 OperationsProposalController::applyViaMutationHandler()(一律以 original 定位目標列)是同一套語義。

同時修掉兩個併發缺口(都是寫測試才跑出來的):

  • codes 回退分支ALTNAME_DATA 同時也在 config('codes.tables') 裡,主連結被擋掉後會落到 elseif ($isCodeResource …),換一條路徑產出 /app/codes/ALTNAME_DATA/…/edit 撞同一個 404。
  • resolveAffectedPeopleResourceTargets()(KIN/ASSOC 的 per-person 連結):提案沒有 audit_logs,會落到 resource_id 回退分支;而已核准的刪除提案有 audit 卻沒有列,$allowEditLink 原本只擋 TYPE_DELETE = 4

另外把 OperationsProposalController::buildCompositeId()_._ 位置式主鍵改成先對齊 CompositePrimaryKey::SCHEMAS 欄序:解析端 parseStoredResourceId() 是按 SCHEMAS 還原,而寫入端的 __key_columns 欄序不保證相同,錯位不會報錯、只會靜默指到別的資料列。格式刻意不換成 query-string——CodesController::buildNamedConditionsFromId() 只認純數字主鍵值,換了會讓含文字主鍵的代碼表從「查得到」變「查不到」。

新增 tests/Feature/OperationsProposalResourceLinkTest.php(6 個案例)釘住上表。

2. 別名分頁補上出處/頁碼/備註欄

排查途中發現的另一件事:PersonBrowserService::tabAltNames() 本來就把 c_sourcec_pagesc_notes 撈出來、序列化進 props,AltNamesTab 卻只渲染 序號/別名(拼音)/別名(中)/類型 四欄——是送到前端就被丟掉的死負載。這三欄都在 AltnameMutationHandler::allowedFields() 裡、可經提案修改,列表看不到會讓使用者以為「沒存進去」。

(已驗證寫入端沒問題:propose → approve 的 create 與 update 兩條路徑,c_notes 落庫值都正確。)

  • tabAltNames() leftJoin TEXT_CODES 補出處書名,與 AltnameEditorc_source label 同源;c_source 的哨兵 0 在 TEXT_CODES 沒有對應列,leftJoin 自然落空、不需另外過濾。
  • 出處優先顯示書名(中/英)、查不到退回 #id;備註限寬 360px 並保留換行(SubresourceTable 外層已有橫向捲動)。
  • 表頭沿用編輯器同一組 i18n key(biogmains.source_fieldpages_entriesnotes_field),列表欄名與編輯器欄位標籤字面一致,不需新增翻譯。

注意:其餘 11 個分頁有同樣的「撈了不顯示」問題(notes 在 12 個分頁全都沒渲染),本 PR 只處理別名,其餘另案。

驗證

  • ./vendor/bin/phpunit 全量 2994 tests / 15861 assertions 綠
  • ./vendor/bin/php-cs-fixer fix 0 fixed
  • npm run build 綠、tsc --noEmit 與 base 同為 21 個既有錯誤(無新增)

小提醒:node_modules 裡的 @tanstack/react-table 若還是 8.21.3(package.json/lockfile 已是 9.1.2,dependabot #2adc213f 之後未重裝),npm run build 會因 DataTable.tsx 用 v9 API 而失敗。跑一次 npm ci 即可,與本 PR 無關。

後續(不在本 PR)

AltnameCreateHandlerAltnameMutationHandlerallowedFields() 裡有四個幻影欄位c_alt_name_pinyin23c_alt_name_role。migration 從未建立(baseline import_cbdb_schema.phpALTNAME_DATA 就是 12 欄),prod 也查不到。白名單放行 → SQL 層才炸,實測是 500 而非 422,而 API.md:960 仍把它們列為對外 update 白名單。測試之所以一直綠,是因為合成表自己把這四欄建了出來。另開 issue 處理。

operations.resource_id 存的是「提案完成後」的主鍵,先於現實寫入:create 提案
核准前那一列不存在、update 提案只要改到任一主鍵成員就是尚不存在的新鍵、delete
提案核准後舊鍵那一列已被刪除。直接拿去開 edit-v2,編輯器查不到列就 abort(404)。
這是全部 12 張複合主鍵人物子資源共通的缺口,不限別名。

- 新增 OperationsController::resolveLinkResourceId():未核准的 update/delete
  提案改以 resource_original 的主鍵指向現存那一列(與核准路徑
  applyViaMutationHandler() 一律以 original 定位同一套語義);未核准的 create
  提案與已核准的 delete 提案不出連結
- codes 回退分支同步改吃 resolveLinkResourceId():ALTNAME_DATA 同時也在
  config('codes.tables') 裡,主連結被擋掉後會落到該分支撞同一個 404
- resolveAffectedPeopleResourceTargets()(KIN/ASSOC per-person 連結)同樣處理:
  提案沒有 audit_logs 會落到 resource_id 回退分支,且已核准的刪除提案有 audit
  卻沒有列
- buildCompositeId() 的 _._ 位置式主鍵改先對齊 CompositePrimaryKey::SCHEMAS 欄序:
  解析端按 SCHEMAS 還原,而 __key_columns 的欄序不保證相同,錯位會靜默指到別列。
  格式刻意不換成 query-string——CodesController::buildNamedConditionsFromId()
  只認純數字主鍵值,換了會讓含文字主鍵的代碼表從「查得到」變「查不到」

已執行 ./vendor/bin/phpunit(2993 tests 全綠)與
./vendor/bin/phpunit --filter OperationsProposalResourceLinkTest
PersonBrowserService::tabAltNames() 原本就把 c_source/c_pages/c_notes 撈出來
送到前端,AltNamesTab 卻只渲染 序號/別名(拼音)/別名(中)/類型 四欄,等於是
送到前端就被丟掉的死負載。這三個欄位都在 AltnameMutationHandler 的 allowedFields
裡、可經提案修改,列表看不到會讓使用者誤以為沒存進去。

- tabAltNames() leftJoin TEXT_CODES 補出處書名(source_title_chn/source_title),
  與 AltnameEditor 的 c_source label 同源;c_source 的哨兵 0 在 TEXT_CODES 沒有
  對應列,leftJoin 自然落空、不需另外過濾
- AltNamesTab 加三欄;出處優先顯示書名(中/英)、查不到退回 #id,備註限寬 360px
  並保留換行(SubresourceTable 外層已有橫向捲動)。表頭沿用編輯器同一組 i18n key
  (biogmains.source_field/pages_entries/notes_field),列表欄名與編輯器欄位標籤一致

已執行 ./vendor/bin/phpunit(2994 tests 全綠)與 npm run build
@chatgpt-codex-connector

This comment was marked as off-topic.

@sudoghut
sudoghut merged commit f306a48 into cbdb-project:develop Aug 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants