identifiers() + ['unit_id' => $context->unitId()]; $actor = $request->user()->id; abort_unless($scope['unit_id'] !== null && $context->userId() === $actor, 403); abort_unless(in_array(implode(':', $scope), config('purchasing-access.initialisation_scopes', []), true), 403); $permissions = app(Permissions::class); $context->selectFor($actor, $scope['tenant_id'], $scope['company_id'], $scope['unit_id']); $permissions->require($actor, $scope['tenant_id'], $scope['company_id'], 'access.manage'); $members = DB::table('company_memberships as m')->join('users as u', 'u.id', '=', 'm.user_id') ->where('m.tenant_id', $scope['tenant_id'])->where('m.company_id', $scope['company_id'])->get(['u.id', 'u.name'])->filter(function ($member) use ($permissions, $scope) { return $permissions->has($member->id, $scope['tenant_id'], $scope['company_id'], 'company.view') && $permissions->has($member->id, $scope['tenant_id'], $scope['company_id'], 'access.manage') && $permissions->has($member->id, $scope['tenant_id'], $scope['company_id'], 'unit.view', $scope['unit_id']); })->values()->all(); return ['scope' => $scope, 'administrators' => $members, 'rights' => AccessOverlay::RIGHTS, 'labels' => AccessOverlay::LABELS, 'initialised' => DB::table('identity_audit')->where($scope)->where('action', 'purchasing.access_initialised')->exists()]; } public function initialise(Request $request): array { $data = $request->validate([ 'operation_key' => 'required|uuid', 'reason' => 'required|string|min:10|max:500', 'administrators' => 'required|array|min:1|max:20', 'administrators.*' => 'array:user_id,rights', 'administrators.*.user_id' => 'required|integer|distinct|min:1', 'administrators.*.rights' => 'required|array|min:1', 'administrators.*.rights.*' => 'required|string|distinct', ]); abort_unless(array_diff(array_keys($request->all()), array_keys($data)) === [], 422); $context = app(CompanyContext::class); $scope = $context->identifiers() + ['unit_id' => $context->unitId()]; $actor = $request->user()->id; abort_unless($scope['unit_id'] !== null && $context->userId() === $actor, 403); // Installed configuration explicitly permits initialisation for this exact scope. $scopeKey = implode(':', $scope); abort_unless(in_array($scopeKey, config('purchasing-access.initialisation_scopes', []), true), 403); foreach ($data['administrators'] as &$admin) { abort_unless(array_diff($admin['rights'], AccessOverlay::RIGHTS) === [], 422); sort($admin['rights']); } unset($admin); usort($data['administrators'], fn ($a, $b) => $a['user_id'] <=> $b['user_id']); $hash = hash('sha256', json_encode($data, JSON_THROW_ON_ERROR)); return DB::transaction(function () use ($request, $scope, $actor, $context, $data, $hash) { DB::table('companies')->where('id', $scope['company_id'])->where('tenant_id', $scope['tenant_id'])->lockForUpdate()->firstOrFail(); $context->selectFor($actor, $scope['tenant_id'], $scope['company_id'], $scope['unit_id']); $permissions = app(Permissions::class); $permissions->require($actor, $scope['tenant_id'], $scope['company_id'], 'access.manage'); if ($request->hasSession()) { $token = (string) $request->session()->get('company_context.token', ''); abort_unless($token !== '' && hash_equals($token, (string) $request->header('X-SGF-Context')), 409); } $old = DB::table('identity_audit')->where($scope)->where('action', 'purchasing.access_initialised')->first(); if ($old) { $details = json_decode($old->details, true, 32, JSON_THROW_ON_ERROR); abort_unless($old->actor_id === $actor && ($details['event_id'] ?? null) === $hash, 409, 'Autoridade inicial já entregue; use a gestão normal de acessos.'); return ['initialised' => true, 'replayed' => true]; } $grants = []; foreach ($data['administrators'] as $admin) { foreach (['company.view', 'access.manage'] as $right) { $permissions->require($admin['user_id'], $scope['tenant_id'], $scope['company_id'], $right); } $permissions->require($admin['user_id'], $scope['tenant_id'], $scope['company_id'], 'unit.view', $scope['unit_id']); abort_unless(DB::table('company_memberships')->where(['user_id' => $admin['user_id'], 'tenant_id' => $scope['tenant_id'], 'company_id' => $scope['company_id']])->exists(), 403); foreach ($admin['rights'] as $right) { abort_unless(in_array($right, Permissions::UNIT, true), 503, 'Catálogo operacional não preparado.'); DB::table('permission_grants')->insertOrIgnore($scope + ['user_id' => $admin['user_id'], 'permission' => $right, 'created_at' => now(), 'updated_at' => now()]); $grants[] = ['user_id' => $admin['user_id'], 'permission' => $right]; } } Audit::record('purchasing.access_initialised', $actor, $scope['tenant_id'], $scope['company_id'], $scope['unit_id'], details: ['reason' => $data['reason'], 'event_id' => $hash, 'grants' => $grants]); return ['initialised' => true, 'replayed' => false]; }); } }