Implemented the output contract and readiness semantics for review packs. Also added spec 348. Includes changes to ChooseEnvironment, CustomerReviewWorkspace, GenerateReviewPackJob and related blade views. Added comprehensive tests. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #419
191 lines
5.7 KiB
PHP
191 lines
5.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Filament\Pages;
|
|
|
|
use App\Models\ManagedEnvironment;
|
|
use App\Models\User;
|
|
use App\Models\UserTenantPreference;
|
|
use App\Services\Tenants\TenantOperabilityService;
|
|
use App\Support\ManagedEnvironmentLinks;
|
|
use App\Support\Tenants\TenantInteractionLane;
|
|
use App\Support\Tenants\TenantLifecyclePresentation;
|
|
use App\Support\Tenants\TenantOperabilityQuestion;
|
|
use App\Support\Workspaces\WorkspaceContext;
|
|
use Filament\Facades\Filament;
|
|
use Filament\Pages\Page;
|
|
use Illuminate\Database\Eloquent\Collection;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use Illuminate\Support\Str;
|
|
|
|
class ChooseEnvironment extends Page
|
|
{
|
|
protected static string $layout = 'filament-panels::components.layout.simple';
|
|
|
|
protected static bool $shouldRegisterNavigation = false;
|
|
|
|
protected static bool $isDiscovered = false;
|
|
|
|
protected static ?string $slug = 'choose-environment';
|
|
|
|
protected string $view = 'filament.pages.choose-environment';
|
|
|
|
public string $search = '';
|
|
|
|
public function getTitle(): string
|
|
{
|
|
return __('localization.shell.choose_environment');
|
|
}
|
|
|
|
/**
|
|
* Disable the simple-layout topbar to prevent lazy-loaded
|
|
* DatabaseNotifications from triggering Livewire update 404s.
|
|
*/
|
|
protected function getLayoutData(): array
|
|
{
|
|
return [
|
|
'hasTopbar' => false,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, ManagedEnvironment>
|
|
*/
|
|
public function getTenants(): Collection
|
|
{
|
|
$user = auth()->user();
|
|
|
|
if (! $user instanceof User) {
|
|
return ManagedEnvironment::query()->whereRaw('1 = 0')->get();
|
|
}
|
|
|
|
$tenants = $user->getTenants(Filament::getCurrentOrDefaultPanel());
|
|
|
|
if ($tenants instanceof Collection) {
|
|
return app(TenantOperabilityService::class)->filterSelectable($tenants);
|
|
}
|
|
|
|
return app(TenantOperabilityService::class)->filterSelectable(collect($tenants));
|
|
}
|
|
|
|
/**
|
|
* @return Collection<int, ManagedEnvironment>
|
|
*/
|
|
public function getVisibleTenants(?Collection $tenants = null): Collection
|
|
{
|
|
$tenants ??= $this->getTenants();
|
|
$search = Str::of($this->search)->trim()->lower()->toString();
|
|
|
|
if ($search === '') {
|
|
return $tenants;
|
|
}
|
|
|
|
return $tenants
|
|
->filter(function (ManagedEnvironment $tenant) use ($search): bool {
|
|
$presentation = $this->tenantLifecyclePresentation($tenant);
|
|
|
|
return collect([
|
|
$tenant->name,
|
|
$tenant->domain,
|
|
$tenant->environment,
|
|
$presentation->label,
|
|
$presentation->shortDescription,
|
|
])
|
|
->filter(fn (mixed $value): bool => is_string($value) && $value !== '')
|
|
->contains(fn (string $value): bool => Str::contains(Str::lower($value), $search));
|
|
})
|
|
->values();
|
|
}
|
|
|
|
public function selectEnvironment(int $tenantId): void
|
|
{
|
|
$user = auth()->user();
|
|
|
|
if (! $user instanceof User) {
|
|
abort(403);
|
|
}
|
|
|
|
$workspaceContext = app(WorkspaceContext::class);
|
|
$workspaceId = $workspaceContext->currentWorkspaceId(request());
|
|
$tenant = null;
|
|
|
|
if ($workspaceId === null) {
|
|
$tenant = ManagedEnvironment::query()->whereKey($tenantId)->first();
|
|
|
|
if ($tenant instanceof ManagedEnvironment) {
|
|
$workspace = $tenant->workspace;
|
|
|
|
if ($workspace !== null && $user->canAccessTenant($tenant)) {
|
|
$workspaceContext->setCurrentWorkspace($workspace, $user, request());
|
|
$workspaceId = (int) $workspace->getKey();
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($workspaceId === null) {
|
|
$this->redirect(route('filament.admin.pages.choose-workspace'));
|
|
|
|
return;
|
|
}
|
|
|
|
if (! $tenant instanceof ManagedEnvironment || (int) $tenant->workspace_id !== $workspaceId) {
|
|
$tenant = ManagedEnvironment::query()
|
|
->where('workspace_id', $workspaceId)
|
|
->whereKey($tenantId)
|
|
->first();
|
|
}
|
|
|
|
if (! $tenant instanceof ManagedEnvironment) {
|
|
abort(404);
|
|
}
|
|
|
|
if (! $user->canAccessTenant($tenant)) {
|
|
abort(404);
|
|
}
|
|
|
|
$outcome = app(TenantOperabilityService::class)->outcomeFor(
|
|
tenant: $tenant,
|
|
question: TenantOperabilityQuestion::SelectorEligibility,
|
|
actor: $user,
|
|
workspaceId: $workspaceId,
|
|
lane: TenantInteractionLane::StandardActiveOperating,
|
|
);
|
|
|
|
if (! $outcome->allowed) {
|
|
abort(404);
|
|
}
|
|
|
|
$this->persistLastTenant($user, $tenant);
|
|
|
|
if (! $workspaceContext->rememberEnvironmentContext($tenant, request())) {
|
|
abort(404);
|
|
}
|
|
|
|
$this->redirect(ManagedEnvironmentLinks::viewUrl($tenant));
|
|
}
|
|
|
|
public function tenantLifecyclePresentation(ManagedEnvironment $tenant): TenantLifecyclePresentation
|
|
{
|
|
return TenantLifecyclePresentation::fromTenant($tenant);
|
|
}
|
|
|
|
private function persistLastTenant(User $user, ManagedEnvironment $tenant): void
|
|
{
|
|
if (Schema::hasColumn('users', 'last_tenant_id')) {
|
|
$user->forceFill(['last_tenant_id' => $tenant->getKey()])->save();
|
|
|
|
return;
|
|
}
|
|
|
|
if (! Schema::hasTable('user_managed_environment_preferences')) {
|
|
return;
|
|
}
|
|
|
|
UserTenantPreference::query()->updateOrCreate(
|
|
['user_id' => $user->getKey(), 'managed_environment_id' => $tenant->getKey()],
|
|
['last_used_at' => now()]
|
|
);
|
|
}
|
|
}
|