diff --git a/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java b/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java index 35547b86..cb57ef16 100644 --- a/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java +++ b/mateclaw-server/src/main/java/vip/mate/workspace/core/config/WorkspaceSchemaMigration.java @@ -60,26 +60,27 @@ public class WorkspaceSchemaMigration implements ApplicationRunner { } /** - * 确保所有现有用户都是默认工作区的成员 + * Ensure all admin users have an owner-role membership in the default workspace. + * Non-admin users must be added explicitly via WorkspaceController.addMember. */ private void ensureDefaultWorkspaceMembership() { try { - // 查找不在默认工作区中的用户 int inserted = jdbcTemplate.update(""" INSERT INTO mate_workspace_member (id, workspace_id, user_id, role, create_time, update_time, deleted) - SELECT u.id, 1, u.id, CASE WHEN u.role = 'admin' THEN 'owner' ELSE u.role END, NOW(), NOW(), 0 + SELECT u.id, 1, u.id, 'owner', NOW(), NOW(), 0 FROM mate_user u WHERE u.deleted = 0 + AND u.role = 'admin' AND NOT EXISTS ( SELECT 1 FROM mate_workspace_member wm WHERE wm.workspace_id = 1 AND wm.user_id = u.id AND wm.deleted = 0 ) """); if (inserted > 0) { - log.info("Added {} existing user(s) to default workspace", inserted); + log.info("Added {} admin user(s) as owner of default workspace", inserted); } } catch (DataAccessException e) { - log.debug("Skipping default workspace membership init: {}", e.getMessage()); + log.debug("Skipping default workspace admin membership init: {}", e.getMessage()); } } } diff --git a/mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql b/mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql new file mode 100644 index 00000000..c569cdb1 --- /dev/null +++ b/mateclaw-server/src/main/resources/db/migration/h2/V60__fix_invalid_workspace_member_roles.sql @@ -0,0 +1,26 @@ +-- RFC-076: clean up invalid workspace_member rows produced by the legacy +-- WorkspaceSchemaMigration.ensureDefaultWorkspaceMembership() insert +-- (issue: https://github.com/matevip/mateclaw/issues/29). + +-- 1) For users who already have a valid membership in another workspace, +-- drop their illegal default-workspace membership. +DELETE FROM mate_workspace_member +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer') + AND user_id IN ( + SELECT user_id FROM ( + SELECT user_id FROM mate_workspace_member + WHERE workspace_id <> 1 + AND deleted = 0 + AND role IN ('owner', 'admin', 'member', 'viewer') + ) t + ); + +-- 2) For orphans whose only membership is the illegal default one, +-- normalize the role to 'member' so they don't get locked out entirely. +UPDATE mate_workspace_member +SET role = 'member', update_time = NOW() +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer'); diff --git a/mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql b/mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql new file mode 100644 index 00000000..c569cdb1 --- /dev/null +++ b/mateclaw-server/src/main/resources/db/migration/mysql/V60__fix_invalid_workspace_member_roles.sql @@ -0,0 +1,26 @@ +-- RFC-076: clean up invalid workspace_member rows produced by the legacy +-- WorkspaceSchemaMigration.ensureDefaultWorkspaceMembership() insert +-- (issue: https://github.com/matevip/mateclaw/issues/29). + +-- 1) For users who already have a valid membership in another workspace, +-- drop their illegal default-workspace membership. +DELETE FROM mate_workspace_member +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer') + AND user_id IN ( + SELECT user_id FROM ( + SELECT user_id FROM mate_workspace_member + WHERE workspace_id <> 1 + AND deleted = 0 + AND role IN ('owner', 'admin', 'member', 'viewer') + ) t + ); + +-- 2) For orphans whose only membership is the illegal default one, +-- normalize the role to 'member' so they don't get locked out entirely. +UPDATE mate_workspace_member +SET role = 'member', update_time = NOW() +WHERE workspace_id = 1 + AND deleted = 0 + AND role NOT IN ('owner', 'admin', 'member', 'viewer');