1<?php
2/* Copyright (c) 1998-2019 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4use ILIAS\Filesystem\Filesystems;
5use ILIAS\FileUpload\FileUpload;
6use ILIAS\HTTP\GlobalHttpState;
7use ILIAS\UI\Factory;
8use ILIAS\UI\Renderer;
9
10/**
11 * Class ilAccessibilityDocumentGUI
12 */
13class ilAccessibilityDocumentGUI implements ilAccessibilityControllerEnabled
14{
15    /** @var ilAccessibilityTableDataProviderFactory */
16    protected $tableDataProviderFactory;
17
18    /** @var ilObjAccessibilitySettings */
19    protected $accs;
20
21    /** @var ilGlobalPageTemplate */
22    protected $tpl;
23
24    /** @var ilCtrl */
25    protected $ctrl;
26
27    /** @var ilLanguage */
28    protected $lng;
29
30    /** @var ilRbacSystem */
31    protected $rbacsystem;
32
33    /** @var ilErrorHandling */
34    protected $error;
35
36    /** @var ilObjUser */
37    protected $user;
38
39    /** @var ilLogger */
40    protected $log;
41
42    /** @var Factory */
43    protected $uiFactory;
44
45    /** @var Renderer */
46    protected $uiRenderer;
47
48    /** @var ILIAS\HTTP\GlobalHttpState */
49    protected $httpState;
50
51    /** @var ilToolbarGUI */
52    protected $toolbar;
53
54    /** @var FileUpload */
55    protected $fileUpload;
56
57    /** @var Filesystems */
58    protected $fileSystems;
59
60    /** @var ilAccessibilityCriterionTypeFactoryInterface */
61    protected $criterionTypeFactory;
62
63    /** @var ilHtmlPurifierInterface */
64    protected $documentPurifier;
65
66    /**
67     * ilAccessibilityDocumentGUI constructor.
68     * @param ilObjAccessibilitySettings                    $accs
69     * @param ilAccessibilityCriterionTypeFactoryInterface $criterionTypeFactory
70     * @param ilGlobalPageTemplate                          $tpl
71     * @param ilObjUser                                     $user
72     * @param ilCtrl                                        $ctrl
73     * @param ilLanguage                                    $lng
74     * @param ilRbacSystem                                  $rbacsystem
75     * @param ilErrorHandling                               $error
76     * @param ilLogger                                      $log
77     * @param ilToolbarGUI                                  $toolbar
78     * @param GlobalHttpState                               $httpState
79     * @param Factory                                       $uiFactory
80     * @param Renderer                                      $uiRenderer
81     * @param Filesystems                                   $fileSystems ,
82     * @param FileUpload                                    $fileUpload
83     * @param ilAccessibilityTableDataProviderFactory    $tableDataProviderFactory
84     * @param ilHtmlPurifierInterface                       $documentPurifier
85     */
86    public function __construct(
87        ilObjAccessibilitySettings $accs,
88        ilAccessibilityCriterionTypeFactoryInterface $criterionTypeFactory,
89        ilGlobalPageTemplate $tpl,
90        ilObjUser $user,
91        ilCtrl $ctrl,
92        ilLanguage $lng,
93        ilRbacSystem $rbacsystem,
94        ilErrorHandling $error,
95        ilLogger $log,
96        ilToolbarGUI $toolbar,
97        GlobalHttpState $httpState,
98        Factory $uiFactory,
99        Renderer $uiRenderer,
100        Filesystems $fileSystems,
101        FileUpload $fileUpload,
102        ilAccessibilityTableDataProviderFactory $tableDataProviderFactory,
103        ilHtmlPurifierInterface $documentPurifier
104    ) {
105        $this->accs = $accs;
106        $this->criterionTypeFactory = $criterionTypeFactory;
107        $this->tpl = $tpl;
108        $this->ctrl = $ctrl;
109        $this->lng = $lng;
110        $this->rbacsystem = $rbacsystem;
111        $this->error = $error;
112        $this->user = $user;
113        $this->log = $log;
114        $this->toolbar = $toolbar;
115        $this->httpState = $httpState;
116        $this->uiFactory = $uiFactory;
117        $this->uiRenderer = $uiRenderer;
118        $this->fileSystems = $fileSystems;
119        $this->fileUpload = $fileUpload;
120        $this->tableDataProviderFactory = $tableDataProviderFactory;
121        $this->documentPurifier = $documentPurifier;
122    }
123
124    /**
125     *
126     */
127    public function executeCommand() : void
128    {
129        $cmd = $this->ctrl->getCmd();
130
131        if (!$this->rbacsystem->checkAccess('read', $this->accs->getRefId())) {
132            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
133        }
134
135        if ($cmd == '' || !method_exists($this, $cmd)) {
136            $cmd = 'showDocuments';
137        }
138        $this->$cmd();
139    }
140
141
142    /**
143     * @throws ilDateTimeException
144     * @throws ilAccessibilityMissingDatabaseAdapterException
145     */
146    protected function showDocuments() : void
147    {
148        if ($this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
149            $addDocumentBtn = $this->uiFactory->button()->primary(
150                $this->lng->txt('acc_add_document_btn_label'),
151                $this->ctrl->getLinkTarget($this, 'showAddDocumentForm')
152            );
153            $this->toolbar->addStickyItem($addDocumentBtn);
154        }
155
156        $documentTableGui = new ilAccessibilityDocumentTableGUI(
157            $this,
158            'showDocuments',
159            $this->criterionTypeFactory,
160            $this->uiFactory,
161            $this->uiRenderer,
162            $this->rbacsystem->checkAccess('write', $this->accs->getRefId())
163        );
164        $documentTableGui->setProvider($this->tableDataProviderFactory->getByContext(ilAccessibilityTableDataProviderFactory::CONTEXT_DOCUMENTS));
165        $documentTableGui->populate();
166
167        $this->tpl->setContent($documentTableGui->getHTML());
168    }
169
170    /**
171     * @param ilAccessibilityDocument $document
172     * @return ilAccessibilityDocumentFormGUI
173     */
174    protected function getDocumentForm(ilAccessibilityDocument $document) : ilAccessibilityDocumentFormGUI
175    {
176        if ($document->getId() > 0) {
177            $this->ctrl->setParameter($this, 'acc_id', $document->getId());
178        }
179
180        $formAction = $this->ctrl->getFormAction($this, 'saveAddDocumentForm');
181        $saveCommand = 'saveAddDocumentForm';
182
183        if ($document->getId() > 0) {
184            $formAction = $this->ctrl->getFormAction($this, 'saveEditDocumentForm');
185            $saveCommand = 'saveEditDocumentForm';
186        }
187
188        $form = new ilAccessibilityDocumentFormGUI(
189            $document,
190            $this->documentPurifier,
191            $this->user,
192            $this->fileSystems->temp(),
193            $this->fileUpload,
194            $formAction,
195            $saveCommand,
196            'showDocuments',
197            $this->rbacsystem->checkAccess('write', $this->accs->getRefId())
198        );
199
200        return $form;
201    }
202
203    /**
204     *
205     */
206    protected function saveAddDocumentForm() : void
207    {
208        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
209            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
210        }
211
212        $form = $this->getDocumentForm(new ilAccessibilityDocument());
213        if ($form->saveObject()) {
214            ilUtil::sendSuccess($this->lng->txt('saved_successfully'), true);
215            if ($form->hasTranslatedInfo()) {
216                ilUtil::sendInfo($form->getTranslatedInfo(), true);
217            }
218            $this->ctrl->redirect($this, 'showDocuments');
219        } elseif ($form->hasTranslatedError()) {
220            ilUtil::sendFailure($form->getTranslatedError());
221        }
222
223        $this->tpl->setContent($form->getHTML());
224    }
225
226    /**
227     *
228     */
229    protected function showAddDocumentForm() : void
230    {
231        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
232            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
233        }
234
235        $form = $this->getDocumentForm(new ilAccessibilityDocument());
236        $this->tpl->setContent($form->getHTML());
237    }
238
239    /**
240     *
241     */
242    protected function showEditDocumentForm() : void
243    {
244        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
245            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
246        }
247
248        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
249
250        $form = $this->getDocumentForm($document);
251        $this->tpl->setContent($form->getHTML());
252    }
253
254    /**
255     *
256     */
257    protected function saveEditDocumentForm() : void
258    {
259        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
260            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
261        }
262
263        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
264
265        $form = $this->getDocumentForm($document);
266        if ($form->saveObject()) {
267            ilUtil::sendSuccess($this->lng->txt('saved_successfully'), true);
268            if ($form->hasTranslatedInfo()) {
269                ilUtil::sendInfo($form->getTranslatedInfo(), true);
270            }
271            $this->ctrl->redirect($this, 'showDocuments');
272        } elseif ($form->hasTranslatedError()) {
273            ilUtil::sendFailure($form->getTranslatedError());
274        }
275
276        $this->tpl->setContent($form->getHTML());
277    }
278
279    /**
280     * @return ilAccessibilityDocument[]
281     */
282    protected function getDocumentsByServerRequest() : array
283    {
284        $documents = [];
285
286        $documentIds = $this->httpState->request()->getParsedBody()['acc_id'] ?? [];
287        if (!is_array($documentIds) || 0 === count($documentIds)) {
288            $documentIds = $this->httpState->request()->getQueryParams()['acc_id'] ? [$this->httpState->request()->getQueryParams()['acc_id']] : [];
289        }
290
291        if (0 === count($documentIds)) {
292            return $documents;
293        }
294
295        $documents = ilAccessibilityDocument::where(
296            ['id' => array_filter(array_map('intval', $documentIds))],
297            ['id' => 'IN']
298        )->getArray();
299
300        return $documents;
301    }
302
303    /**
304     * @param array $documents
305     * @return ilAccessibilityDocument
306     * @throws UnexpectedValueException
307     */
308    protected function getFirstDocumentFromList(array $documents) : ilAccessibilityDocument
309    {
310        if (1 !== count($documents)) {
311            throw new UnexpectedValueException('Expected exactly one document in list');
312        }
313
314        $document = new ilAccessibilityDocument(0);
315        $document = $document->buildFromArray(current($documents));
316
317        return $document;
318    }
319
320    /**
321     *
322     */
323    protected function deleteDocuments() : void
324    {
325        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
326            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
327        }
328
329        $documents = $this->getDocumentsByServerRequest();
330        if (0 === count($documents)) {
331            $this->showDocuments();
332            return;
333        } else {
334            $documents = array_map(function (array $data) {
335                $document = new ilAccessibilityDocument(0);
336                $document = $document->buildFromArray($data);
337
338                return $document;
339            }, $documents);
340        }
341
342        $isDeletionRequest = (bool) ($this->httpState->request()->getQueryParams()['delete'] ?? false);
343        if ($isDeletionRequest) {
344            $this->processDocumentDeletion($documents);
345
346            $this->ctrl->redirect($this);
347        } else {
348            $this->ctrl->setParameter($this, 'delete', 1);
349            $confirmation = new ilConfirmationGUI();
350            $confirmation->setFormAction($this->ctrl->getFormAction($this, 'deleteDocuments'));
351            $confirmation->setConfirm($this->lng->txt('confirm'), 'deleteDocuments');
352            $confirmation->setCancel($this->lng->txt('cancel'), 'showDocuments');
353
354            $confirmation->setHeaderText($this->lng->txt('acc_sure_delete_documents_p'));
355            if (1 === count($documents)) {
356                $confirmation->setHeaderText($this->lng->txt('acc_sure_delete_documents_s'));
357            }
358
359            foreach ($documents as $document) {
360                /** @var $document ilAccessibilityDocument */
361                $confirmation->addItem('acc_id[]', $document->getId(), implode(' | ', [
362                    $document->getTitle()
363                ]));
364            }
365
366            $this->tpl->setContent($confirmation->getHTML());
367        }
368    }
369
370    /**
371     * @param array $documents
372     */
373    protected function processDocumentDeletion(array $documents) : void
374    {
375        foreach ($documents as $document) {
376            /** @var $document ilAccessibilityDocument */
377            $document->delete();
378        }
379
380        ilUtil::sendSuccess($this->lng->txt('acc_deleted_documents_p'), true);
381        if (1 === count($documents)) {
382            ilUtil::sendSuccess($this->lng->txt('acc_deleted_documents_s'), true);
383        }
384    }
385
386    /**
387     *
388     */
389    protected function deleteDocument() : void
390    {
391        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
392            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
393        }
394
395        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
396
397        $this->processDocumentDeletion([$document]);
398
399        $this->ctrl->redirect($this);
400    }
401
402    /**
403     *
404     */
405    protected function saveDocumentSorting() : void
406    {
407        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
408            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
409        }
410
411        $sorting = $this->httpState->request()->getParsedBody()['sorting'] ?? [];
412        if (!is_array($sorting) || 0 === count($sorting)) {
413            $this->showDocuments();
414            return;
415        }
416
417        asort($sorting, SORT_NUMERIC);
418
419        $position = 0;
420        foreach ($sorting as $documentId => $ignoredSortValue) {
421            if (!is_numeric($documentId)) {
422                continue;
423            }
424
425            try {
426                $document = new ilAccessibilityDocument((int) $documentId);
427                $document->setSorting(++$position);
428                $document->store();
429            } catch (ilException $e) {
430                // Empty catch block
431            }
432        }
433
434        ilUtil::sendSuccess($this->lng->txt('acc_saved_sorting'), true);
435        $this->ctrl->redirect($this);
436    }
437
438    /**
439     * @param ilAccessibilityDocument                    $document
440     * @param ilAccessibilityDocumentCriterionAssignment $criterionAssignment
441     * @return ilAccessibilityCriterionFormGUI
442     */
443    protected function getCriterionForm(
444        ilAccessibilityDocument $document,
445        ilAccessibilityDocumentCriterionAssignment $criterionAssignment
446    ) : ilAccessibilityCriterionFormGUI {
447        $this->ctrl->setParameter($this, 'acc_id', $document->getId());
448
449        if ($criterionAssignment->getId() > 0) {
450            $this->ctrl->setParameter($this, 'crit_id', $criterionAssignment->getId());
451        }
452
453        $formAction = $this->ctrl->getFormAction($this, 'saveAttachCriterionForm');
454        $saveCommand = 'saveAttachCriterionForm';
455
456        if ($criterionAssignment->getId() > 0) {
457            $formAction = $this->ctrl->getFormAction($this, 'saveChangeCriterionForm');
458            $saveCommand = 'saveChangeCriterionForm';
459        }
460
461        $form = new ilAccessibilityCriterionFormGUI(
462            $document,
463            $criterionAssignment,
464            $this->criterionTypeFactory,
465            $this->user,
466            $formAction,
467            $saveCommand,
468            'showDocuments'
469        );
470
471        return $form;
472    }
473
474    /**
475     *
476     */
477    protected function saveAttachCriterionForm() : void
478    {
479        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
480            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
481        }
482
483        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
484
485        $form = $this->getCriterionForm($document, new ilAccessibilityDocumentCriterionAssignment());
486        if ($form->saveObject()) {
487            ilUtil::sendSuccess($this->lng->txt('acc_doc_crit_attached'), true);
488            $this->ctrl->redirect($this, 'showDocuments');
489        } elseif ($form->hasTranslatedError()) {
490            ilUtil::sendFailure($form->getTranslatedError());
491        }
492
493        $this->tpl->setContent($form->getHTML());
494    }
495
496    /**
497     *
498     */
499    protected function showAttachCriterionForm() : void
500    {
501        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
502            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
503        }
504
505        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
506
507        $form = $this->getCriterionForm($document, new ilAccessibilityDocumentCriterionAssignment());
508        $this->tpl->setContent($form->getHTML());
509    }
510
511    /**
512     *
513     */
514    protected function showChangeCriterionForm() : void
515    {
516        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
517            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
518        }
519
520        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
521
522        $criterionId = $this->httpState->request()->getQueryParams()['crit_id'] ?? 0;
523        if (!is_numeric($criterionId) || $criterionId < 1) {
524            $this->showDocuments();
525            return;
526        }
527
528        $criterionAssignment = array_values(array_filter(
529            $document->criteria(),
530            function (ilAccessibilityDocumentCriterionAssignment $criterionAssignment) use ($criterionId) {
531                return $criterionAssignment->getId() == $criterionId;
532            }
533        ))[0];
534
535        $form = $this->getCriterionForm($document, $criterionAssignment);
536        $this->tpl->setContent($form->getHTML());
537    }
538
539    /**
540     *
541     */
542    protected function saveChangeCriterionForm() : void
543    {
544        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
545            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
546        }
547
548        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
549
550        $criterionId = $this->httpState->request()->getQueryParams()['crit_id'] ?? 0;
551        if (!is_numeric($criterionId) || $criterionId < 1) {
552            $this->showDocuments();
553            return;
554        }
555
556        $criterionAssignment = array_values(array_filter(
557            $document->criteria(),
558            function (ilAccessibilityDocumentCriterionAssignment $criterionAssignment) use ($criterionId) {
559                return $criterionAssignment->getId() == $criterionId;
560            }
561        ))[0];
562
563        $form = $this->getCriterionForm($document, $criterionAssignment);
564        if ($form->saveObject()) {
565            ilUtil::sendSuccess($this->lng->txt('acc_doc_crit_changed'), true);
566            $this->ctrl->redirect($this, 'showDocuments');
567        } elseif ($form->hasTranslatedError()) {
568            ilUtil::sendFailure($form->getTranslatedError());
569        }
570
571        $this->tpl->setContent($form->getHTML());
572    }
573
574    /**
575     *
576     */
577    public function detachCriterionAssignment() : void
578    {
579        if (!$this->rbacsystem->checkAccess('write', $this->accs->getRefId())) {
580            $this->error->raiseError($this->lng->txt('permission_denied'), $this->error->MESSAGE);
581        }
582
583        $document = $this->getFirstDocumentFromList($this->getDocumentsByServerRequest());
584
585        $criterionId = $this->httpState->request()->getQueryParams()['crit_id'] ?? 0;
586        if (!is_numeric($criterionId) || $criterionId < 1) {
587            $this->showDocuments();
588            return;
589        }
590
591        $criterionAssignment = array_values(array_filter(
592            $document->criteria(),
593            function (ilAccessibilityDocumentCriterionAssignment $criterionAssignment) use ($criterionId) {
594                return $criterionAssignment->getId() == $criterionId;
595            }
596        ))[0];
597
598        $document->detachCriterion($criterionAssignment);
599        $document->update();
600
601        ilUtil::sendSuccess($this->lng->txt('acc_doc_crit_detached'), true);
602        $this->ctrl->redirect($this, 'showDocuments');
603    }
604}
605