Passed
Pull Request — master (#6357)
by
unknown
08:17
created

CertificateController::view()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 42
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 21
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 42
rs 8.6506
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Framework\Container;
10
use Chamilo\CoreBundle\Helpers\UserHelper;
11
use Chamilo\CoreBundle\Repository\GradebookCertificateRepository;
12
use Chamilo\CoreBundle\Settings\SettingsManager;
13
use Mpdf\Mpdf;
14
use Mpdf\MpdfException;
15
use Mpdf\Output\Destination;
16
use RuntimeException;
17
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
18
use Symfony\Component\HttpFoundation\Response;
19
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
20
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
21
use Symfony\Component\Routing\Attribute\Route;
22
23
#[Route('/certificates')]
24
class CertificateController extends AbstractController
25
{
26
    public function __construct(
27
        private readonly GradebookCertificateRepository $certificateRepository,
28
        private readonly SettingsManager $settingsManager,
29
        private readonly UserHelper $userHelper
30
    ) {}
31
32
    #[Route('/{hash}.html', name: 'chamilo_certificate_public_view', methods: ['GET'])]
33
    public function view(string $hash): Response
34
    {
35
        // Build the expected certificate filename from the hash
36
        $filename = $hash.'.html';
37
38
        // Look up the certificate record by its path
39
        $certificate = $this->certificateRepository->findOneBy([
40
            'pathCertificate' => $filename,
41
        ]);
42
43
        if (!$certificate) {
44
            throw new NotFoundHttpException('The requested certificate does not exist.');
45
        }
46
47
        // Check if public access is globally allowed and certificate is marked as published
48
        $allowPublic = 'true' === $this->settingsManager->getSetting('course.allow_public_certificates', true);
49
        $allowSessionAdmin = 'true' === $this->settingsManager->getSetting('certificate.session_admin_can_download_all_certificates', true);
50
        $user = $this->userHelper->getCurrent();
51
52
        if (
53
            (!$allowPublic || !$certificate->getPublish())
54
            && (!$allowSessionAdmin || !$user->hasRole('ROLE_SESSION_MANAGER'))
55
        ) {
56
            throw new AccessDeniedHttpException('The requested certificate is not public.');
57
        }
58
59
        // Fetch the actual certificate file from personal files using its title
60
        $personalFileRepo = Container::getPersonalFileRepository();
61
        $personalFile = $personalFileRepo->findOneBy(['title' => $filename]);
62
63
        if (!$personalFile) {
64
            throw new NotFoundHttpException('The certificate file was not found.');
65
        }
66
67
        // Read the certificate HTML content and sanitize for print compatibility
68
        $content = $personalFileRepo->getResourceFileContent($personalFile);
69
        $content = str_replace(' media="screen"', '', $content);
70
71
        // Return the certificate as a raw HTML response
72
        return new Response('<!DOCTYPE html>'.$content, 200, [
73
            'Content-Type' => 'text/html; charset=UTF-8',
74
        ]);
75
    }
76
77
    #[Route('/{hash}.pdf', name: 'chamilo_certificate_public_pdf', methods: ['GET'])]
78
    public function downloadPdf(string $hash): Response
79
    {
80
        $filename = $hash.'.html';
81
82
        $certificate = $this->certificateRepository->findOneBy(['pathCertificate' => $filename]);
83
        if (!$certificate) {
84
            throw $this->createNotFoundException('The requested certificate does not exist.');
85
        }
86
87
        $allowPublic = 'true' === $this->settingsManager->getSetting('course.allow_public_certificates', true);
88
        $allowSessionAdmin = 'true' === $this->settingsManager->getSetting('certificate.session_admin_can_download_all_certificates', true);
89
        $user = $this->userHelper->getCurrent();
90
91
        if (
92
            (!$allowPublic || !$certificate->getPublish())
93
            && (!$allowSessionAdmin || !$user->hasRole('ROLE_SESSION_MANAGER'))
94
        ) {
95
            throw $this->createAccessDeniedException('The requested certificate is not public.');
96
        }
97
98
        $personalFileRepo = Container::getPersonalFileRepository();
99
        $personalFile = $personalFileRepo->findOneBy(['title' => $filename]);
100
        if (!$personalFile) {
101
            throw $this->createNotFoundException('The certificate file was not found.');
102
        }
103
104
        $html = $personalFileRepo->getResourceFileContent($personalFile);
105
        $html = str_replace(' media="screen"', '', $html);
106
107
        try {
108
            $mpdf = new Mpdf([
109
                'format' => 'A4',
110
                'tempDir' => api_get_path(SYS_ARCHIVE_PATH).'mpdf/',
111
            ]);
112
            $mpdf->WriteHTML($html);
113
114
            return new Response(
115
                $mpdf->Output('certificate.pdf', Destination::DOWNLOAD),
116
                200,
117
                [
118
                    'Content-Type' => 'application/pdf',
119
                    'Content-Disposition' => 'attachment; filename="certificate.pdf"',
120
                ]
121
            );
122
        } catch (MpdfException $e) {
123
            throw new RuntimeException('Failed to generate PDF: '.$e->getMessage(), 500, $e);
124
        }
125
    }
126
}
127