Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.96% covered (success)
97.96%
48 / 49
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ResolvePublicPortalQuery
97.96% covered (success)
97.96%
48 / 49
50.00% covered (danger)
50.00%
1 / 2
6
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
97.92% covered (success)
97.92%
47 / 48
0.00% covered (danger)
0.00%
0 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\ClientPortal\Application\Queries;
6
7use ImovelZapAi\ClientPortal\Application\Services\PortalTokenService;
8use ImovelZapAi\ClientPortal\Domain\Enums\PortalActivityEvent;
9use ImovelZapAi\ClientPortal\Domain\Exceptions\ClientPortalException;
10use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\DocumentCommentModel;
11use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\PortalSessionModel;
12use ImovelZapAi\Tenancy\Infrastructure\Persistence\Eloquent\TenantModel;
13use ImovelZapAi\Publishing\Infrastructure\Persistence\Eloquent\TenantPublishingConfigModel;
14
15final class ResolvePublicPortalQuery
16{
17    public function __construct(
18        private readonly PortalTokenService $tokens,
19    ) {}
20
21    /**
22     * @return array<string, mixed>
23     */
24    public function execute(string $plainToken, ?string $ip = null, ?string $userAgent = null): array
25    {
26        $resolved = $this->tokens->resolve($plainToken);
27        $portal = $resolved['portal'];
28        $token = $resolved['token'];
29
30        PortalSessionModel::query()->updateOrCreate(
31            [
32                'tenant_id' => $portal->tenant_id,
33                'client_portal_id' => $portal->id,
34                'portal_access_token_id' => $token->id,
35                'ip' => $ip,
36            ],
37            [
38                'user_agent' => $userAgent ? substr($userAgent, 0, 512) : null,
39                'started_at' => now(),
40                'last_seen_at' => now(),
41            ],
42        );
43
44        $portal->load(['requestedDocuments.upload.currentVersion', 'requestedDocuments.upload.reviews']);
45
46        $tenant = TenantModel::query()->find($portal->tenant_id);
47        $branding = TenantPublishingConfigModel::query()
48            ->where('tenant_id', $portal->tenant_id)
49            ->first();
50
51        $comments = DocumentCommentModel::query()
52            ->where('client_portal_id', $portal->id)
53            ->where('visible_to_client', true)
54            ->orderByDesc('created_at')
55            ->get();
56
57        $recentOpen = \ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\PortalActivityModel::query()
58            ->where('client_portal_id', $portal->id)
59            ->where('event', PortalActivityEvent::PortalOpened)
60            ->where('created_at', '>=', now()->subHour())
61            ->exists();
62
63        if (! $recentOpen) {
64            app(\ImovelZapAi\ClientPortal\Application\Services\PortalActivityWriter::class)->write(
65                $portal->tenant_id,
66                $portal->id,
67                PortalActivityEvent::PortalOpened,
68                actorType: 'client',
69                message: 'Cliente abriu o portal.',
70            );
71        }
72
73        if ($tenant === null) {
74            throw ClientPortalException::notFound();
75        }
76
77        return [
78            'portal' => $portal,
79            'tenant_name' => $branding?->company_name ?: $tenant->name,
80            'logo_url' => $branding?->logo_url,
81            'comments' => $comments,
82            'progress_percent' => $portal->progressPercent(),
83        ];
84    }
85}