Skip to content
Clone

fix(chat): resolve room parents against the dir table

rooms.parent_id holds the id of a directory node (dir.id), and
update_room only accepts a same-space DirKind::Dir target - but the
entity declared the column as a self-reference, so sync_schema created
`fk-rooms-parent_id -> rooms(id)`. A folder id therefore passed every
application check and was then rejected by the database: filing a
channel into a folder answered 500 (SQLSTATE 23503) and the feature had
never succeeded once - no room row anywhere carries a parent.

The relation now declares belongs_to dir::Entity, so the rebuilt
constraint points at the table that actually owns those ids. Because
sync only adds missing keys and treats a same-named constraint as
already present, schema_pre_sync.sql drops the wrong one first, guarded
on confrelid so it is a no-op once the constraint is correct, and resets
any parent_id that cannot name a dir node.

parent_id additionally becomes three-state (see the previous commit):
null puts the room back at the space root, absent leaves it alone.

The same pre-sync block also adds user_preferences.board_view_mode, which
the board-view commit below consumes.
ZhenYi committed
parent cf002db commit 403e9f0 Browse files

3 files changed

+43 −10

File tree 3
Modified lib/chat/src/services/rooms.rs View lib/chat/src/services/rooms.rs
@@ -70,7 +70,7 @@
7070 pub position: Option<i64>,
7171 /// Move the room under another directory node of the same space; `null` puts
7272 /// it back at the space root. Absent means "leave the parent alone".
73 #[serde(default)]
73 #[serde(default, deserialize_with = "export::serde_patch::deserialize_opt_opt")]
7474 pub parent_id: Option<Option<Uuid>>,
7575}
7676
@@ -811,7 +811,10 @@
811811 &pending,
812812 invitee,
813813 NotificationType::Invite,
814 i18n::catalog::notification_channel_invite_title(self.recipient_locale(invitee).await).to_string(),
814 i18n::catalog::notification_channel_invite_title(
815 self.recipient_locale(invitee).await,
816 )
817 .to_string(),
815818 None,
816819 Some(data),
817820 Some(caller),
Modified lib/models/src/room/rooms.rs View lib/models/src/room/rooms.rs
@@ -76,14 +76,12 @@
7676 pub space: BelongsTo<Option<super::super::space::spaces::Entity>>,
7777 #[sea_orm(belongs_to, from = "owner_id", to = "uid")]
7878 pub owner: BelongsTo<super::super::users::user::Entity>,
79 #[sea_orm(
80 self_ref,
81 relation_enum = "Parent",
82 relation_reverse = "Children",
83 from = "parent_id",
84 to = "id"
85 )]
86 pub parent: HasOne<Entity>,
79 /// 频道所在目录节点。`parent_id` 指向 `dir(id)` 而非本表:侧边栏的
80 /// 「拖进文件夹」把频道挂在目录节点下,写入前 `update_room` 会校验目标
81 /// 必须是同空间的 `DirKind::Dir` 节点。挂成 self_ref 会让这个外键在
82 /// 数据库里永远匹配不上(dir 的 id 不是 rooms 的 id),写入必然被拒。
83 #[sea_orm(belongs_to, from = "parent_id", to = "id")]
84 pub parent: BelongsTo<Option<super::super::dir::dirs::Entity>>,
8785 #[sea_orm(has_many)]
8886 pub members: HasMany<super::room_members::Entity>,
8987 #[sea_orm(has_many)]
Modified lib/models/schema_pre_sync.sql View lib/models/schema_pre_sync.sql
@@ -21,6 +21,33 @@
2121-- scheduled messages feature removed; drop the legacy table before sync
2222DROP TABLE IF EXISTS user_scheduled_message;
2323
24-- rooms.parent_id used to be declared as a self-reference, so sync created
25-- `fk-rooms-parent_id -> rooms(id)`. The column actually points at a directory
26-- node (dir.id) — update_room validates the target is a same-space DirKind::Dir
27-- row before writing — so every attempt to file a channel into a folder was
28-- rejected by that constraint and the feature never once succeeded. Sync only
29-- adds missing foreign keys and treats a same-named constraint as present, so
30-- the wrong one has to go before the corrected entity can be built.
31-- Guarded on confrelid so this is a no-op once the constraint is correct.
32DO $$ BEGIN
33 IF to_regclass('rooms') IS NOT NULL
34 AND to_regclass('dir') IS NOT NULL
35 AND EXISTS (
36 SELECT 1 FROM pg_constraint
37 WHERE conname = 'fk-rooms-parent_id'
38 AND conrelid = 'rooms'::regclass
39 AND confrelid <> 'dir'::regclass
40 ) THEN
41 ALTER TABLE rooms DROP CONSTRAINT "fk-rooms-parent_id";
42 -- Defensive: anything the old constraint let through cannot be a dir
43 -- node, so it is not a valid folder. Reset it instead of letting the
44 -- corrected foreign key fail to build.
45 UPDATE rooms SET parent_id = NULL
46 WHERE parent_id IS NOT NULL
47 AND NOT EXISTS (SELECT 1 FROM dir WHERE dir.id = rooms.parent_id);
48 END IF;
49END $$;
50
2451-- pipeline_run was replaced by workflow_run/workflow_job/workflow_step
2552DROP INDEX IF EXISTS idx_workflow_run_repo;
2653DROP INDEX IF EXISTS idx_workflow_run_concurrency;
@@ -61,6 +88,11 @@
6188 END IF;
6289END $$;
6390DO $$ BEGIN
91 IF to_regclass('user_preferences') IS NOT NULL THEN
92 ALTER TABLE user_preferences ADD COLUMN IF NOT EXISTS board_view_mode VARCHAR NOT NULL DEFAULT 'board';
93 END IF;
94END $$;
95DO $$ BEGIN
6496 IF to_regclass('chat_message_reminder') IS NOT NULL THEN
6597 ALTER TABLE chat_message_reminder ADD COLUMN IF NOT EXISTS note TEXT;
6698 END IF;