Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m45s
Implemented the first version of review output resolve actions. Included a ReviewOutputResolveActionMapper, commands to seed browser fixtures, updated CustomerReviewWorkspace, EnvironmentReviewResource, UI enforcement, and related views. Also added extensive unit, feature, and browser tests, and updated the design coverage matrix.
165 lines
6.7 KiB
PHP
165 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services\EnvironmentReviews;
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\EnvironmentReview;
|
|
use App\Models\User;
|
|
use App\Models\Workspace;
|
|
use App\Models\WorkspaceMembership;
|
|
use App\Services\Auth\CapabilityResolver;
|
|
use App\Services\Auth\ManagedEnvironmentAccessScopeResolver;
|
|
use App\Support\Auth\Capabilities;
|
|
use App\Support\EnvironmentReviewStatus;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
final class EnvironmentReviewRegisterService
|
|
{
|
|
public function __construct(
|
|
private readonly CapabilityResolver $capabilityResolver,
|
|
private readonly ManagedEnvironmentAccessScopeResolver $managedEnvironmentAccessScopeResolver,
|
|
) {}
|
|
|
|
/**
|
|
* @return array<int, ManagedEnvironment>
|
|
*/
|
|
public function authorizedTenants(User $user, Workspace $workspace): array
|
|
{
|
|
$query = ManagedEnvironment::query()
|
|
->where('managed_environments.workspace_id', (int) $workspace->getKey());
|
|
|
|
$this->managedEnvironmentAccessScopeResolver->applyWorkspaceScopeToQuery(
|
|
query: $query,
|
|
user: $user,
|
|
workspaceId: (int) $workspace->getKey(),
|
|
qualifiedEnvironmentColumn: 'managed_environments.id',
|
|
);
|
|
|
|
$tenants = $query
|
|
->orderBy('managed_environments.name')
|
|
->get();
|
|
|
|
$this->capabilityResolver->primeMemberships($user, $tenants->modelKeys());
|
|
|
|
return $tenants
|
|
->filter(fn (ManagedEnvironment $tenant): bool => $this->capabilityResolver->can($user, $tenant, Capabilities::ENVIRONMENT_REVIEW_VIEW))
|
|
->keyBy(static fn (ManagedEnvironment $tenant): int => (int) $tenant->getKey())
|
|
->all();
|
|
}
|
|
|
|
public function query(User $user, Workspace $workspace): Builder
|
|
{
|
|
$tenantIds = array_keys($this->authorizedTenants($user, $workspace));
|
|
|
|
return EnvironmentReview::query()
|
|
->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack'])
|
|
->forWorkspace((int) $workspace->getKey())
|
|
->whereIn('managed_environment_id', $tenantIds === [] ? [-1] : $tenantIds)
|
|
->latest('generated_at')
|
|
->latest('id');
|
|
}
|
|
|
|
public function latestPublishedQuery(User $user, Workspace $workspace): Builder
|
|
{
|
|
$tenantIds = array_keys($this->authorizedTenants($user, $workspace));
|
|
|
|
$rankedReviews = EnvironmentReview::query()
|
|
->select([
|
|
'environment_reviews.id',
|
|
'environment_reviews.managed_environment_id',
|
|
'environment_reviews.published_at',
|
|
'environment_reviews.generated_at',
|
|
])
|
|
->selectRaw('ROW_NUMBER() OVER (PARTITION BY managed_environment_id ORDER BY published_at DESC, generated_at DESC, id DESC) as rn')
|
|
->forWorkspace((int) $workspace->getKey())
|
|
->whereIn('managed_environment_id', $tenantIds === [] ? [-1] : $tenantIds)
|
|
->published();
|
|
|
|
$latestPublishedIds = DB::query()
|
|
->fromSub($rankedReviews, 'ranked_environment_reviews')
|
|
->where('rn', 1)
|
|
->select('id');
|
|
|
|
return EnvironmentReview::query()
|
|
->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack'])
|
|
->forWorkspace((int) $workspace->getKey())
|
|
->whereIn('environment_reviews.id', $latestPublishedIds)
|
|
->orderByDesc('published_at')
|
|
->orderByDesc('generated_at')
|
|
->orderByDesc('id');
|
|
}
|
|
|
|
public function customerWorkspaceLifecycleReviewQuery(User $user, Workspace $workspace): Builder
|
|
{
|
|
return EnvironmentReview::query()
|
|
->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack', 'supersededByReview'])
|
|
->forWorkspace((int) $workspace->getKey())
|
|
->whereIn('environment_reviews.id', $this->customerWorkspaceLifecycleReviewIdsQuery($user, $workspace))
|
|
->orderByDesc('published_at')
|
|
->orderByDesc('generated_at')
|
|
->orderByDesc('id');
|
|
}
|
|
|
|
public function customerWorkspaceTenantQuery(User $user, Workspace $workspace): Builder
|
|
{
|
|
$tenantIds = array_keys($this->authorizedTenants($user, $workspace));
|
|
|
|
return ManagedEnvironment::query()
|
|
->where('workspace_id', (int) $workspace->getKey())
|
|
->whereIn('id', $tenantIds === [] ? [-1] : $tenantIds)
|
|
->whereHas('environmentReviews', fn ($query) => $query->whereIn(
|
|
'environment_reviews.id',
|
|
$this->customerWorkspaceLifecycleReviewIdsQuery($user, $workspace),
|
|
))
|
|
->with([
|
|
'environmentReviews' => fn ($query) => $query
|
|
->with(['tenant', 'evidenceSnapshot', 'currentExportReviewPack', 'supersededByReview'])
|
|
->whereIn('environment_reviews.id', $this->customerWorkspaceLifecycleReviewIdsQuery($user, $workspace))
|
|
->orderByDesc('published_at')
|
|
->orderByDesc('generated_at')
|
|
->orderByDesc('id'),
|
|
])
|
|
->orderBy('name');
|
|
}
|
|
|
|
public function canAccessWorkspace(User $user, Workspace $workspace): bool
|
|
{
|
|
return WorkspaceMembership::query()
|
|
->where('workspace_id', (int) $workspace->getKey())
|
|
->where('user_id', (int) $user->getKey())
|
|
->exists();
|
|
}
|
|
|
|
private function customerWorkspaceLifecycleReviewIdsQuery(User $user, Workspace $workspace): \Illuminate\Database\Query\Builder
|
|
{
|
|
$tenantIds = array_keys($this->authorizedTenants($user, $workspace));
|
|
|
|
$rankedReviews = EnvironmentReview::query()
|
|
->select([
|
|
'environment_reviews.id',
|
|
'environment_reviews.managed_environment_id',
|
|
'environment_reviews.published_at',
|
|
'environment_reviews.generated_at',
|
|
])
|
|
->selectRaw('ROW_NUMBER() OVER (PARTITION BY managed_environment_id ORDER BY COALESCE(published_at, generated_at) DESC, generated_at DESC, id DESC) as rn')
|
|
->forWorkspace((int) $workspace->getKey())
|
|
->whereIn('managed_environment_id', $tenantIds === [] ? [-1] : $tenantIds)
|
|
->where(function (Builder $query): void {
|
|
$query->published()
|
|
->orWhere(function (Builder $query): void {
|
|
$query
|
|
->where('status', EnvironmentReviewStatus::Superseded->value)
|
|
->whereNotNull('superseded_by_review_id');
|
|
});
|
|
});
|
|
|
|
return DB::query()
|
|
->fromSub($rankedReviews, 'ranked_customer_workspace_reviews')
|
|
->where('rn', 1)
|
|
->select('id');
|
|
}
|
|
}
|