feat(projects-bulk): scope.filter resolver + 500-limit guard

Refactor inline scope resolution from ProjectController::bulk() into
ProjectService::resolveBulkScope (BULK_MAX=500 constant). Adds 2 tests:
scope.filter->ids mapping and >500 rejection (12 total, all pass).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-12 14:59:59 +03:00
parent c6eae16282
commit 64d8daede7
4 changed files with 68 additions and 27 deletions
@@ -143,32 +143,13 @@ class ProjectController extends Controller
public function bulk(BulkProjectActionRequest $request): JsonResponse
{
$tenantId = $request->user()->tenant_id;
$action = $request->validated('action');
$ids = $this->projects->resolveBulkScope(
$tenantId,
$request->validated('ids'),
$request->validated('scope.filter'),
);
// Resolve target IDs: explicit list takes priority; otherwise expand from scope.filter.
if ($request->has('scope.filter')) {
$filter = $request->validated('scope.filter') ?? [];
$query = Project::where('tenant_id', $tenantId);
if (! empty($filter['signal_type'])) {
$query->where('signal_type', $filter['signal_type']);
}
if (! empty($filter['status'])) {
match ($filter['status']) {
'active' => $query->whereNull('archived_at')->where('is_active', true),
'paused' => $query->whereNull('archived_at')->where('is_active', false),
'archived' => $query->whereNotNull('archived_at'),
default => null,
};
}
if (! empty($filter['search'])) {
$query->where('name', 'ilike', '%'.$filter['search'].'%');
}
$ids = $query->limit(500)->pluck('id')->all();
} else {
$ids = $request->validated('ids') ?? [];
}
if (count($ids) > 500) {
if (count($ids) > ProjectService::BULK_MAX) {
return response()->json([
'errors' => ['scope' => ['Слишком много проектов под фильтр (>500). Уточните фильтры или выберите вручную.']],
], 422);
@@ -176,7 +157,7 @@ class ProjectController extends Controller
$payload = array_merge($request->validated(), ['ids' => $ids]);
$result = $this->projects->bulkAction($tenantId, $action, $payload);
$result = $this->projects->bulkAction($tenantId, $request->validated('action'), $payload);
return response()->json($result);
}