From daca3848220e0ca2c3be6aaca92f48480e005f19 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Mon, 1 Jun 2026 15:02:03 +0000 Subject: [PATCH] =?UTF-8?q?feat(todo):=20=E5=BE=85=E5=8A=9E=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E6=9D=83=E9=99=90=E6=94=BE=E5=BC=80=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=91=98=EF=BC=88=E4=BB=BB=E6=84=8F=E7=BE=A4?= =?UTF-8?q?=E5=8F=AF=E8=AE=BE/=E5=8F=96=E6=B6=88=E4=BB=96=E4=BA=BA?= =?UTF-8?q?=E5=BE=85=E5=8A=9E=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - checkTodoOwnerPermission 最高优先级放行系统管理员,覆盖无群主的全员群等场景 - 同步设/取消待办、到点提醒接口报错文案与系统设置描述 - 补充管理员放行测试(user/project/全员群) Co-Authored-By: Claude Opus 4.8 --- app/Http/Controllers/Api/DialogController.php | 2 +- app/Models/WebSocketDialog.php | 4 +++ app/Models/WebSocketDialogMsg.php | 2 +- language/original-api.txt | 2 +- language/original-web.txt | 2 +- .../setting/components/SystemSetting.vue | 2 +- tests/Feature/TodoSetPermissionTest.php | 34 ++++++++++++++++++- 7 files changed, 42 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php index 047d9d3c3..39fbf331f 100755 --- a/app/Http/Controllers/Api/DialogController.php +++ b/app/Http/Controllers/Api/DialogController.php @@ -2647,7 +2647,7 @@ class DialogController extends AbstractController if (Base::settingFind('system', 'todo_set_permission') === 'close') { $others = array_diff($userids, [$user->userid]); if ($others && !$dialog->checkTodoOwnerPermission($user->userid)) { - return Base::retError('仅群主、项目/任务负责人可设置或取消他人待办'); + return Base::retError('仅群主、项目/任务负责人或系统管理员可设置或取消他人待办'); } } // diff --git a/app/Models/WebSocketDialog.php b/app/Models/WebSocketDialog.php index ce546037e..34a73b6f7 100644 --- a/app/Models/WebSocketDialog.php +++ b/app/Models/WebSocketDialog.php @@ -723,6 +723,10 @@ class WebSocketDialog extends AbstractModel if ($userid <= 0) { return false; } + // 系统管理员:可管理任意会话的他人待办(与管理员全局管理能力一致,覆盖无群主的全员群等) + if (User::find($userid)?->isAdmin()) { + return true; + } // 群主 / 群管理员 if ($this->isOwner($userid)) { return true; diff --git a/app/Models/WebSocketDialogMsg.php b/app/Models/WebSocketDialogMsg.php index 44705f71a..909c2c224 100644 --- a/app/Models/WebSocketDialogMsg.php +++ b/app/Models/WebSocketDialogMsg.php @@ -428,7 +428,7 @@ class WebSocketDialogMsg extends AbstractModel $affected = array_unique(array_merge($cancel, $setup)); // 本次真正影响到的用户 $others = array_diff($affected, [$sender]); // 排除"自己" if ($others && !$dialog->checkTodoOwnerPermission($sender)) { - return Base::retError('仅群主、项目/任务负责人可设置或取消他人待办'); + return Base::retError('仅群主、项目/任务负责人或系统管理员可设置或取消他人待办'); } } // diff --git a/language/original-api.txt b/language/original-api.txt index 12acfe474..b082c9d6c 100644 --- a/language/original-api.txt +++ b/language/original-api.txt @@ -976,7 +976,7 @@ LDAP 用户缺少邮箱属性,请联系管理员配置 负责人不能任命为项目管理员 普通成员不能移出群主或群管理员 只有群主、群管理员或邀请人可以移出成员 -仅群主、项目/任务负责人可设置或取消他人待办 +仅群主、项目/任务负责人或系统管理员可设置或取消他人待办 请选择文件 仅支持 xls/xlsx/csv 文件 文件中没有可导入的数据 diff --git a/language/original-web.txt b/language/original-web.txt index 18e0eca0f..9d15d1d59 100644 --- a/language/original-web.txt +++ b/language/original-web.txt @@ -2395,7 +2395,7 @@ AI任务分析 部门管理员同步失败 待办设置权限 允许:所有成员可设置/取消他人待办。 -禁止:仅本人、群主(含群管理员)、项目负责人(含项目管理员)、任务负责人可设置/取消待办。 +禁止:仅本人、系统管理员、群主(含群管理员)、项目负责人(含项目管理员)、任务负责人可设置/取消待办。 批量导入用户 请按模板填写后上传,列顺序:邮箱、昵称、初始密码、职位(选填);单次最多导入500条。 diff --git a/resources/assets/js/pages/manage/setting/components/SystemSetting.vue b/resources/assets/js/pages/manage/setting/components/SystemSetting.vue index 54556385d..e56b5410c 100644 --- a/resources/assets/js/pages/manage/setting/components/SystemSetting.vue +++ b/resources/assets/js/pages/manage/setting/components/SystemSetting.vue @@ -213,7 +213,7 @@ {{$L('禁止')}}
{{$L('允许:所有成员可设置/取消他人待办。')}}
-
{{$L('禁止:仅本人、群主(含群管理员)、项目负责人(含项目管理员)、任务负责人可设置/取消待办。')}}
+
{{$L('禁止:仅本人、系统管理员、群主(含群管理员)、项目负责人(含项目管理员)、任务负责人可设置/取消待办。')}}
diff --git a/tests/Feature/TodoSetPermissionTest.php b/tests/Feature/TodoSetPermissionTest.php index 29b66aebf..af3d82a14 100644 --- a/tests/Feature/TodoSetPermissionTest.php +++ b/tests/Feature/TodoSetPermissionTest.php @@ -35,6 +35,15 @@ class TodoSetPermissionTest extends TestCase return $user; } + /** 系统管理员(identity 含 admin) */ + private function makeAdmin(string $email): User + { + $user = $this->makeUser($email); + $user->identity = Base::arrayImplode(['admin']); + $user->save(); + return $user->fresh(); + } + /** 普通群(group_type=user),设置群主与群管理员 */ private function makeUserGroup(int $ownerUserid, array $members, array $deputyUserids = []): WebSocketDialog { @@ -137,6 +146,29 @@ class TodoSetPermissionTest extends TestCase $this->assertFalse($taskDialog->checkTodoOwnerPermission($member->userid), '普通成员应拒绝'); } + public function test_admin_allowed_in_any_group() + { + $admin = $this->makeAdmin('t_admin@test.local'); + $owner = $this->makeUser('t_admin_o@test.local'); + $member = $this->makeUser('t_admin_m@test.local'); + + // 普通群:管理员既非群主也非成员,仍放行;普通成员仍拒绝 + $userGroup = $this->makeUserGroup($owner->userid, [$member->userid]); + $this->assertTrue($userGroup->checkTodoOwnerPermission($admin->userid), '管理员在普通群应放行'); + $this->assertFalse($userGroup->checkTodoOwnerPermission($member->userid), '普通成员仍应拒绝'); + + // 项目群:管理员非项目负责人,仍放行 + $project = $this->makeProjectWithDialog($owner->userid, [$member->userid]); + $pdialog = WebSocketDialog::find($project->dialog_id); + $this->assertTrue($pdialog->checkTodoOwnerPermission($admin->userid), '管理员在项目群应放行'); + + // 全员群(无群主):管理员放行,普通成员拒绝 + $allGroup = WebSocketDialog::createGroup('Test_all', [$owner->userid, $member->userid], 'all')->fresh(); + $this->assertSame(0, (int)$allGroup->owner_id, '全员群应无群主'); + $this->assertTrue($allGroup->checkTodoOwnerPermission($admin->userid), '管理员在全员群应放行'); + $this->assertFalse($allGroup->checkTodoOwnerPermission($member->userid), '全员群普通成员应拒绝'); + } + /** * 镜像 WebSocketDialogMsg::toggleTodoMsg 内的权限闸门决策。 * @param string $switch 开关值 open|close @@ -234,7 +266,7 @@ class TodoSetPermissionTest extends TestCase $this->assertTrue(Base::isError($res), '被拦截路径应返回错误响应'); $this->assertSame(0, $res['ret']); - $this->assertStringContainsString('仅群主、项目/任务负责人可设置或取消他人待办', $res['msg']); + $this->assertStringContainsString('仅群主、项目/任务负责人或系统管理员可设置或取消他人待办', $res['msg']); // 被拦截后不应写入任何待办记录 $this->assertSame(0, WebSocketDialogMsgTodo::whereMsgId($msg->id)->count());