更新
This commit is contained in:
@@ -16,7 +16,7 @@ if (!$admin) {
|
||||
throw new RuntimeException('未找到 root 管理员,无法执行数据范围冒烟测试');
|
||||
}
|
||||
$overview = WecomPromotionLogic::overview((int) $admin['id'], $admin, 'https://example.test');
|
||||
foreach (['meta', 'config', 'summary', 'pools', 'links', 'member_options', 'department_options'] as $key) {
|
||||
foreach (['meta', 'config', 'summary', 'pools', 'links', 'member_options', 'operator_options', 'department_options'] as $key) {
|
||||
if (!array_key_exists($key, $overview)) {
|
||||
throw new RuntimeException("overview 缺少 {$key}");
|
||||
}
|
||||
@@ -42,19 +42,40 @@ if ($memberIds !== []) {
|
||||
if (!is_array($overview['department_options'])) {
|
||||
throw new RuntimeException('department_options 必须是部门树数组');
|
||||
}
|
||||
foreach ($overview['pools'] as $pool) {
|
||||
foreach (['operators', 'operator_admin_ids', 'can_operate', 'can_manage_access', 'can_delete'] as $key) {
|
||||
if (!array_key_exists($key, $pool)) {
|
||||
throw new RuntimeException("pools 缺少共享操作权限字段 {$key}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scopedAdmin = Db::name('admin')->where('root', 0)->whereNull('delete_time')->order('id', 'asc')->find();
|
||||
if ($scopedAdmin) {
|
||||
$visibleIds = DataScopeService::getVisibleAdminIds((int) $scopedAdmin['id'], $scopedAdmin);
|
||||
$scopedOverview = WecomPromotionLogic::overview((int) $scopedAdmin['id'], $scopedAdmin, 'https://example.test');
|
||||
if ($visibleIds !== null) {
|
||||
$scopedPoolIds = array_values(array_filter(array_map('intval', array_column($scopedOverview['pools'], 'id'))));
|
||||
$sharedPoolMemberIds = $scopedPoolIds === []
|
||||
? []
|
||||
: array_map('intval', Db::name('qywx_promotion_pool_member')
|
||||
->whereIn('pool_id', $scopedPoolIds)
|
||||
->whereNull('delete_time')
|
||||
->column('admin_id'));
|
||||
foreach ($scopedOverview['member_options'] as $member) {
|
||||
if (!in_array((int) $member['id'], $visibleIds, true)) {
|
||||
if (!in_array((int) $member['id'], $visibleIds, true)
|
||||
&& !in_array((int) $member['id'], $sharedPoolMemberIds, true)) {
|
||||
throw new RuntimeException('member_options 泄露了当前角色或部门范围外的成员');
|
||||
}
|
||||
}
|
||||
foreach ($scopedOverview['operator_options'] as $operator) {
|
||||
if (!in_array((int) $operator['id'], $visibleIds, true)) {
|
||||
throw new RuntimeException('operator_options 泄露了当前角色或部门范围外的账号');
|
||||
}
|
||||
}
|
||||
foreach ($scopedOverview['pools'] as $pool) {
|
||||
if (!in_array((int) $pool['owner_admin_id'], $visibleIds, true)) {
|
||||
if (!in_array((int) $pool['owner_admin_id'], $visibleIds, true)
|
||||
&& !in_array((int) $scopedAdmin['id'], array_map('intval', $pool['operator_admin_ids'] ?? []), true)) {
|
||||
throw new RuntimeException('pools 泄露了当前角色或部门范围外的数据');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$root = dirname(__DIR__, 2);
|
||||
$logicPath = __DIR__ . '/../app/adminapi/logic/firstvisit/WecomPromotionLogic.php';
|
||||
$customerLogicPath = __DIR__ . '/../app/adminapi/logic/firstvisit/WecomAcquisitionCustomerLogic.php';
|
||||
$controllerPath = __DIR__ . '/../app/adminapi/controller/firstvisit/WecomPromotionController.php';
|
||||
$apiPath = $root . '/admin/src/api/first_visit.ts';
|
||||
$viewPath = $root . '/admin/src/views/first_visit/wecom_promotion/index.vue';
|
||||
$migrationPath = $root . '/server/sql/1.9.20260828/add_wecom_promotion_pool_operators.sql';
|
||||
|
||||
$sources = [];
|
||||
foreach (compact('logicPath', 'customerLogicPath', 'controllerPath', 'apiPath', 'viewPath', 'migrationPath') as $name => $path) {
|
||||
$source = file_get_contents($path);
|
||||
if (!is_string($source)) {
|
||||
throw new RuntimeException("无法读取 {$name}: {$path}");
|
||||
}
|
||||
$sources[$name] = $source;
|
||||
}
|
||||
|
||||
$migration = $sources['migrationPath'];
|
||||
foreach (['qywx_promotion_pool_operator', 'uk_pool_admin', 'granted_by_admin_id'] as $needle) {
|
||||
if (!str_contains($migration, $needle)) {
|
||||
throw new RuntimeException("共享操作人迁移缺少 {$needle}");
|
||||
}
|
||||
}
|
||||
|
||||
$logic = $sources['logicPath'];
|
||||
foreach (['batchSetOperators', 'applyPoolAccessScope', 'isPoolOperator', 'can_manage_access', 'operator_options'] as $needle) {
|
||||
if (!str_contains($logic, $needle)) {
|
||||
throw new RuntimeException("获客助手共享权限逻辑缺少 {$needle}");
|
||||
}
|
||||
}
|
||||
$deleteStart = strpos($logic, 'public static function deletePool(');
|
||||
$deleteEnd = strpos($logic, 'public static function batchSetOperators(', $deleteStart === false ? 0 : $deleteStart);
|
||||
if ($deleteStart === false || $deleteEnd === false) {
|
||||
throw new RuntimeException('无法定位 deletePool/batchSetOperators');
|
||||
}
|
||||
$deleteMethod = substr($logic, $deleteStart, $deleteEnd - $deleteStart);
|
||||
if (!str_contains($deleteMethod, "assertScopedRow('qywx_promotion_pool', \$id, \$adminId, \$adminInfo, false)")) {
|
||||
throw new RuntimeException('共享操作人不得永久删除分流方案');
|
||||
}
|
||||
|
||||
if (!str_contains($sources['customerLogicPath'], 'operatorPoolIds($adminId)')
|
||||
|| !str_contains($sources['customerLogicPath'], "whereOr('p.id', 'in', \$operatorPoolIds)")) {
|
||||
throw new RuntimeException('共享操作人尚未接入获客客户统计权限');
|
||||
}
|
||||
if (!str_contains($sources['controllerPath'], 'public function batchSetOperators()')) {
|
||||
throw new RuntimeException('控制器缺少批量设置操作人接口');
|
||||
}
|
||||
if (!str_contains($sources['apiPath'], '/firstvisit.wecomPromotion/batchSetOperators')) {
|
||||
throw new RuntimeException('前端 API 缺少批量设置操作人接口');
|
||||
}
|
||||
foreach (['批量设置访问操作', '添加操作人', '移除操作人', 'selectedPoolIds', 'can_manage_access'] as $needle) {
|
||||
if (!str_contains($sources['viewPath'], $needle)) {
|
||||
throw new RuntimeException("前端共享权限交互缺少 {$needle}");
|
||||
}
|
||||
}
|
||||
|
||||
echo "WECOM_PROMOTION_POOL_OPERATOR_CONTRACT_OK\n";
|
||||
Reference in New Issue
Block a user