1<?php
2/* Copyright (c) 1998-2018 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4use ILIAS\UI\Factory;
5use ILIAS\UI\Renderer;
6
7/**
8 * @ingroup ServicesCertificate
9 * @author  Niels Theen <ntheen@databay.de>
10 * @ilCtrl_IsCalledBy ilUserCertificateGUI: ilAchievementsGUI
11 */
12class ilUserCertificateGUI
13{
14    /** @var ilTemplate */
15    private $template;
16
17    /** @var ilCtrl */
18    private $controller;
19
20    /** @var ilLanguage */
21    private $language;
22
23    /** @var ilUserCertificateRepository|null */
24    private $userCertificateRepository;
25
26    /** @var ilObjUser|null */
27    private $user;
28
29    /** @var \GuzzleHttp\Psr7\Request|null|\Psr\Http\Message\ServerRequestInterface */
30    private $request;
31
32    /** @var ilLogger */
33    private $certificateLogger;
34
35    /** @var ilSetting */
36    protected $certificateSettings;
37
38    /** @var Factory */
39    protected $uiFactory;
40
41    /** @var Renderer */
42    protected $uiRenderer;
43
44    /** @var ilAccessHandler */
45    protected $access;
46
47    const SORTATION_SESSION_KEY = 'my_certificates_sorting';
48
49    /**
50     * @var array
51     */
52    protected $sortationOptions = [
53        'title_ASC' => 'cert_sortable_by_title_asc',
54        'title_DESC' => 'cert_sortable_by_title_desc',
55        'date_ASC' => 'cert_sortable_by_issue_date_asc',
56        'date_DESC' => 'cert_sortable_by_issue_date_desc',
57    ];
58
59    /** @var string */
60    protected $defaultSorting = 'date_DESC';
61
62    /** @var \ILIAS\Filesystem\Filesystem */
63    private $filesystem;
64
65    /**
66     * @var ilCertificateMigrationValidator|null
67     */
68    private $migrationVisibleValidator;
69
70    /**
71     * @param ilTemplate|null $template
72     * @param ilCtrl|null $controller
73     * @param ilLanguage|null $language
74     * @param ilObjUser $user
75     * @param ilUserCertificateRepository|null $userCertificateRepository
76     * @param \GuzzleHttp\Psr7\Request|null $request
77     * @param ilLogger $certificateLogger
78     * @param ilSetting|null $certificateSettings
79     * @param Factory|null $uiFactory
80     * @param Renderer|null $uiRenderer
81     * @param \ilAccessHandler|null $access
82     * @param \ILIAS\Filesystem\Filesystem|null $filesystem
83     * @param ilCertificateMigrationValidator|null $migrationVisibleValidator
84     */
85    public function __construct(
86        ilTemplate $template = null,
87        ilCtrl $controller = null,
88        ilLanguage $language = null,
89        ilObjUser $user = null,
90        ilUserCertificateRepository $userCertificateRepository = null,
91        GuzzleHttp\Psr7\Request $request = null,
92        ilLogger $certificateLogger = null,
93        ilSetting $certificateSettings = null,
94        Factory $uiFactory = null,
95        Renderer $uiRenderer = null,
96        \ilAccessHandler $access = null,
97        \ILIAS\Filesystem\Filesystem $filesystem = null,
98        ilCertificateMigrationValidator $migrationVisibleValidator = null
99    ) {
100        global $DIC;
101
102        $logger = $DIC->logger()->cert();
103
104        if ($template === null) {
105            $template = $DIC->ui()->mainTemplate();
106        }
107        $this->template = $template;
108
109        if ($controller === null) {
110            $controller = $DIC->ctrl();
111        }
112        $this->controller = $controller;
113
114        if ($language === null) {
115            $language = $DIC->language();
116        }
117        $this->language = $language;
118
119        if ($userCertificateRepository === null) {
120            $userCertificateRepository = new ilUserCertificateRepository($DIC->database(), $logger);
121        }
122        $this->userCertificateRepository = $userCertificateRepository;
123
124        if ($user === null) {
125            $user = $DIC->user();
126        }
127        $this->user = $user;
128
129        if ($request === null) {
130            $request = $DIC->http()->request();
131        }
132        $this->request = $request;
133
134        if ($certificateLogger === null) {
135            $certificateLogger = $DIC->logger()->cert();
136        }
137        $this->certificateLogger = $certificateLogger;
138
139        if ($certificateSettings === null) {
140            $certificateSettings = new ilSetting("certificate");
141        }
142        $this->certificateSettings = $certificateSettings;
143
144        if (null === $uiFactory) {
145            $uiFactory = $DIC->ui()->factory();
146        }
147        $this->uiFactory = $uiFactory;
148
149        if (null === $uiRenderer) {
150            $uiRenderer = $DIC->ui()->renderer();
151        }
152        $this->uiRenderer = $uiRenderer;
153
154        if (null === $access) {
155            $access = $DIC->access();
156        }
157        $this->access = $access;
158
159        if (null === $filesystem) {
160            $filesystem = $DIC->filesystem()->web();
161        }
162        $this->filesystem = $filesystem;
163
164        if (null === $migrationVisibleValidator) {
165            $migrationVisibleValidator = new ilCertificateMigrationValidator($this->certificateSettings);
166        }
167        $this->migrationVisibleValidator = $migrationVisibleValidator;
168
169        $this->language->loadLanguageModule('cert');
170    }
171
172    /**
173     * @return string
174     */
175    private function getDefaultCommand() : string
176    {
177        return 'listCertificates';
178    }
179
180    /**
181     * @return bool
182     * @throws ilDateTimeException
183     * @throws ilException
184     */
185    public function executeCommand()
186    {
187        $nextClass = $this->controller->getNextClass($this);
188        $cmd = $this->controller->getCmd();
189
190        if (!$this->certificateSettings->get('active')) {
191            $this->controller->returnToParent($this);
192        }
193
194        $this->template->setTitle($this->language->txt('obj_cert'));
195
196        switch ($nextClass) {
197            case 'ilcertificatemigrationgui':
198                $migrationGui = new \ilCertificateMigrationGUI();
199                $resultMessageString = $this->controller->forwardCommand($migrationGui);
200                $this->template->setMessage(\ilTemplate::MESSAGE_TYPE_SUCCESS, $resultMessageString, true);
201                $this->listCertificates(true);
202                break;
203
204            default:
205                if (!method_exists($this, $cmd)) {
206                    $cmd = $this->getDefaultCommand();
207                }
208                $this->{$cmd}();
209        }
210
211        return true;
212    }
213
214    /**
215     * @param bool $migrationWasStarted
216     * @throws ilDateTimeException
217     * @throws ilWACException
218     */
219    public function listCertificates(bool $migrationWasStarted = false)
220    {
221        global $DIC;
222
223        if (!$this->certificateSettings->get('active')) {
224            $this->controller->redirect($this);
225            return;
226        }
227
228        $this->template->setBodyClass('iosMyCertificates');
229
230        $showMigrationBox = $this->migrationVisibleValidator->isMigrationAvailable(
231            $this->user,
232            new \ilCertificateMigration($this->user->getId())
233        );
234        if (!$migrationWasStarted && true === $showMigrationBox) {
235            $migrationUiEl = new \ilCertificateMigrationUIElements();
236            $startMigrationCommand = $this->controller->getLinkTargetByClass(
237                ['ilCertificateMigrationGUI'],
238                'startMigrationAndReturnMessage',
239                false,
240                true,
241                false
242            );
243            $messageBoxHtml = $migrationUiEl->getMigrationMessageBox($startMigrationCommand);
244
245            $this->template->setCurrentBlock('mess');
246            $this->template->setVariable('MESSAGE', $messageBoxHtml);
247            $this->template->parseCurrentBlock('mess');
248        }
249
250        $provider = new ilUserCertificateTableProvider(
251            $DIC->database(),
252            $this->certificateLogger,
253            $this->controller,
254            $this->language->txt('certificate_no_object_title')
255        );
256
257        $sorting = $this->getCurrentSortation();
258        $data = $provider->fetchDataSet(
259            $this->user->getId(),
260            [
261                'order_field' => explode('_', $sorting)[0],
262                'order_direction' => explode('_', $sorting)[1]
263            ],
264            []
265        );
266
267        $uiComponents = [];
268
269        if (count($data['items']) > 0) {
270            $sortationOptions = [];
271            $cards = [];
272
273            foreach ($this->sortationOptions as $fieldAndDirection => $lngVariable) {
274                $sortationOptions[$fieldAndDirection] = $this->language->txt($lngVariable);
275            }
276
277            $sortViewControl = $this->uiFactory
278                ->viewControl()
279                ->sortation($sortationOptions)
280                ->withLabel($this->language->txt($this->sortationOptions[$sorting]))
281                ->withTargetURL($this->controller->getLinkTarget($this, 'applySortation'), 'sort_by');
282            $uiComponents[] = $sortViewControl;
283
284            foreach ($data['items'] as $certificateData) {
285                $thumbnailImagePath = $certificateData['thumbnail_image_path'];
286                $imagePath = ilUtil::getWebspaceDir() . $thumbnailImagePath;
287                if ($thumbnailImagePath === null
288                    || $thumbnailImagePath === ''
289                    || !$this->filesystem->has($thumbnailImagePath)
290                ) {
291                    $imagePath = \ilUtil::getImagePath('icon_cert.svg');
292                }
293
294                $cardImage = $this->uiFactory->image()->standard(
295                    ilWACSignedPath::signFile($imagePath),
296                    $certificateData['title']
297                );
298
299
300                $sections = [];
301
302                if (strlen($certificateData['description']) > 0) {
303                    $sections[] = $this->uiFactory->listing()->descriptive([
304                        $this->language->txt('cert_description_label') => $certificateData['description']
305                    ]);
306                }
307
308
309                $oldDatePresentationStatus = \ilDatePresentation::useRelativeDates();
310                \ilDatePresentation::setUseRelativeDates(true);
311                $sections[] = $this->uiFactory->listing()->descriptive([
312                    $this->language->txt('cert_issued_on_label') => \ilDatePresentation::formatDate(
313                        new \ilDateTime($certificateData['date'], \IL_CAL_UNIX)
314                    )
315                ]);
316                \ilDatePresentation::setUseRelativeDates($oldDatePresentationStatus);
317
318                $objectTypeIcon = $this->uiFactory
319                    ->icon()
320                    ->standard($certificateData['obj_type'], $certificateData['obj_type'], 'small');
321
322                $objectTitle = $certificateData['title'];
323                $refIds = \ilObject::_getAllReferences($certificateData['obj_id']);
324                if (count($refIds) > 0) {
325                    foreach ($refIds as $refId) {
326                        if ($this->access->checkAccess('read', '', $refId)) {
327                            $objectTitle = $this->uiRenderer->render(
328                                $this->uiFactory->link()->standard($objectTitle, \ilLink::_getLink($refId))
329                            );
330                            break;
331                        }
332                    }
333                }
334
335                $sections[] = $this->uiFactory->listing()->descriptive([$this->language->txt('cert_object_label') => implode('', [
336                    $this->uiRenderer->render($objectTypeIcon),
337                    $objectTitle
338                ])]);
339
340                $this->controller->setParameter($this, 'certificate_id', $certificateData['id']);
341                $downloadHref = $this->controller->getLinkTarget($this, 'download');
342                $this->controller->clearParameters($this);
343                $sections[] = $this->uiFactory->button()->standard('Download', $downloadHref);
344
345                $card = $this->uiFactory
346                    ->card()
347                    ->standard($certificateData['title'], $cardImage)
348                    ->withSections($sections);
349
350                $cards[] = $card;
351            }
352
353            $deck = $this->uiFactory->deck($cards);
354
355            $uiComponents[] = $this->uiFactory->divider()->horizontal();
356
357            $uiComponents[] = $deck;
358        } else {
359            \ilUtil::sendInfo($this->language->txt('cert_currently_no_certs'));
360        }
361
362        $this->template->setContent($this->uiRenderer->render($uiComponents));
363    }
364
365    /**
366     * @return string
367     */
368    protected function getCurrentSortation() : string
369    {
370        $sorting = \ilSession::get(self::SORTATION_SESSION_KEY);
371        if (!array_key_exists($sorting, $this->sortationOptions)) {
372            $sorting = $this->defaultSorting;
373        }
374
375        return $sorting;
376    }
377
378    /**
379     *
380     */
381    protected function applySortation()
382    {
383        $sorting = $this->request->getQueryParams()['sort_by'] ?? $this->defaultSorting;
384        if (!array_key_exists($sorting, $this->sortationOptions)) {
385            $sorting = $this->defaultSorting;
386        }
387        \ilSession::set(self::SORTATION_SESSION_KEY, $sorting);
388
389        $this->listCertificates();
390    }
391
392    /**
393     * @throws \ilException
394     */
395    public function download()
396    {
397        global $DIC;
398
399        $user = $DIC->user();
400        $language = $DIC->language();
401
402        $userCertificateRepository = new ilUserCertificateRepository(null, $this->certificateLogger);
403        $pdfGenerator = new ilPdfGenerator($userCertificateRepository, $this->certificateLogger);
404
405        $userCertificateId = (int) $this->request->getQueryParams()['certificate_id'];
406
407        try {
408            $userCertificate = $userCertificateRepository->fetchCertificate($userCertificateId);
409            if ((int) $userCertificate->getUserId() !== (int) $user->getId()) {
410                throw new ilException(sprintf('User "%s" tried to access certificate: "%s"', $user->getLogin(), $userCertificateId));
411            }
412        } catch (ilException $exception) {
413            $this->certificateLogger->warning($exception->getMessage());
414            ilUtil::sendFailure($language->txt('cert_error_no_access'));
415            $this->listCertificates();
416            return;
417        }
418
419        $pdfAction = new ilCertificatePdfAction(
420            $this->certificateLogger,
421            $pdfGenerator,
422            new ilCertificateUtilHelper(),
423            $this->language->txt('error_creating_certificate_pdf')
424        );
425
426        $pdfAction->downloadPdf($userCertificate->getUserId(), $userCertificate->getObjId());
427
428        $this->listCertificates();
429    }
430}
431