Passed
Push — dependabot/npm_and_yarn/nanoid... ( aaf2c9...c4aa90 )
by
unknown
14:37 queued 06:22
created

ValidationTokenController::getUserId()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Entity\User;
10
use Chamilo\CoreBundle\Entity\ValidationToken;
11
use Chamilo\CoreBundle\Repository\Node\UserRepository;
12
use Chamilo\CoreBundle\Repository\TicketRelUserRepository;
13
use Chamilo\CoreBundle\Repository\TicketRepository;
14
use Chamilo\CoreBundle\Repository\TrackEDefaultRepository;
15
use Chamilo\CoreBundle\Repository\ValidationTokenRepository;
16
use Chamilo\CoreBundle\ServiceHelper\ValidationTokenHelper;
17
use InvalidArgumentException;
18
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
use Symfony\Component\HttpFoundation\Response;
21
use Symfony\Component\Routing\Annotation\Route;
22
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
23
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
24
25
#[Route('/validate')]
26
class ValidationTokenController extends AbstractController
27
{
28
    public function __construct(
29
        private readonly ValidationTokenHelper $validationTokenHelper,
30
        private readonly ValidationTokenRepository $tokenRepository,
31
        private readonly TrackEDefaultRepository $trackEDefaultRepository,
32
        private readonly TicketRepository $ticketRepository,
33
        private readonly UserRepository $userRepository,
34
        private readonly TicketRelUserRepository $ticketRelUserRepository,
35
        private readonly TokenStorageInterface $tokenStorage,
36
        private readonly RequestStack $requestStack
37
    ) {}
38
39
    #[Route('/{type}/{hash}', name: 'chamilo_core_validate_token')]
40
    public function validate(string $type, string $hash): Response
41
    {
42
        $userId = $this->requestStack->getCurrentRequest()->query->get('user_id');
43
        $userId = null !== $userId ? (int) $userId : null;
44
45
        $token = $this->tokenRepository->findOneBy([
46
            'type' => $this->validationTokenHelper->getTypeId($type),
47
            'hash' => $hash,
48
        ]);
49
50
        if (!$token) {
51
            throw $this->createNotFoundException('Invalid token.');
52
        }
53
54
        // Process the action related to the token type
55
        $this->processAction($token, $userId);
56
57
        // Remove the used token
58
        $this->tokenRepository->remove($token, true);
59
60
        // Register the token usage event
61
        $this->registerTokenUsedEvent($token);
62
63
        if ('ticket' === $type) {
64
            $ticketId = $token->getResourceId();
65
66
            return $this->redirect('/main/ticket/ticket_details.php?ticket_id='.$ticketId);
67
        }
68
69
        return $this->render('@ChamiloCore/Validation/success.html.twig', [
70
            'type' => $type,
71
        ]);
72
    }
73
74
    #[Route('/test/generate-token/{type}/{resourceId}', name: 'test_generate_token')]
75
    public function testGenerateToken(string $type, int $resourceId): Response
76
    {
77
        $typeId = $this->validationTokenHelper->getTypeId($type);
78
        $token = new ValidationToken($typeId, $resourceId);
79
        $this->tokenRepository->save($token, true);
80
81
        $validationLink = $this->generateUrl('validate_token', [
82
            'type' => $type,
83
            'hash' => $token->getHash(),
84
        ], UrlGeneratorInterface::ABSOLUTE_URL);
85
86
        return new Response("Generated token: {$token->getHash()}<br>Validation link: <a href='{$validationLink}'>{$validationLink}</a>");
87
    }
88
89
    /**
90
     * Processes the action associated with the given token type.
91
     */
92
    private function processAction(ValidationToken $token, ?int $userId): void
93
    {
94
        switch ($token->getType()) {
95
            case ValidationTokenHelper::TYPE_TICKET:
96
                $this->unsubscribeUserFromTicket($token->getResourceId(), $userId);
97
98
                break;
99
100
            default:
101
                throw new InvalidArgumentException('Unrecognized token type');
102
        }
103
    }
104
105
    /**
106
     * Unsubscribes a user from a ticket.
107
     */
108
    private function unsubscribeUserFromTicket(int $ticketId, ?int $userId): void
109
    {
110
        if (!$userId) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $userId of type integer|null is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
111
            throw $this->createAccessDeniedException('User not authenticated.');
112
        }
113
114
        $ticket = $this->ticketRepository->find($ticketId);
115
        $user = $this->userRepository->find($userId);
116
117
        if ($ticket && $user) {
118
            $this->ticketRelUserRepository->unsubscribeUserFromTicket($user, $ticket);
119
            $this->trackEDefaultRepository->registerTicketUnsubscribeEvent($ticketId, $userId);
120
        } else {
121
            throw $this->createNotFoundException('Ticket or User not found.');
122
        }
123
    }
124
125
    /**
126
     * Registers the usage event of a validation token.
127
     */
128
    private function registerTokenUsedEvent(ValidationToken $token): void
129
    {
130
        $userId = $this->getUserId();
131
        $this->trackEDefaultRepository->registerTokenUsedEvent($token, $userId);
132
    }
133
134
    /**
135
     * Retrieves the current authenticated user's ID.
136
     */
137
    private function getUserId(): ?int
138
    {
139
        $user = $this->tokenStorage->getToken()?->getUser();
140
141
        return $user instanceof User ? $user->getId() : null;
142
    }
143
}
144