Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 192
0.00% covered (danger)
0.00%
0 / 22
CRAP
0.00% covered (danger)
0.00%
0 / 1
DeliveryServer
0.00% covered (danger)
0.00%
0 / 192
0.00% covered (danger)
0.00%
0 / 22
1722
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getCurrentDeliveryExecution
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 index
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 getViewDataFromRequest
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
20
 _initDeliveryExecution
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
6
 initDeliveryExecution
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
12
 runDeliveryExecution
0.00% covered (danger)
0.00%
0 / 48
0.00% covered (danger)
0.00%
0 / 1
42
 finishDeliveryExecution
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
6
 setTemplate
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 initResultServer
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 showControls
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getReturnUrl
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 getfinishDeliveryExecutionUrl
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getAuthorizationProvider
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 verifyDeliveryStartAuthorized
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 verifyDeliveryExecutionAuthorized
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 logout
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 getDeliveryServer
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getExecutionService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDeliveryFieldsService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 overrideInterfaceLanguage
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
20
 resetOverwrittenLanguage
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3/**
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg
19 *                         (under the project TAO & TAO2);
20 *               2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung
21 *                         (under the project TAO-TRANSFER);
22 *               2009-2012 (update and modification) Public Research Centre Henri Tudor
23 *                         (under the project TAO-SUSTAIN & TAO-DEV);
24 */
25
26namespace oat\taoDelivery\controller;
27
28use tao_helpers_Display;
29use common_exception_NotFound;
30use common_exception_Unauthorized;
31use common_ext_Extension;
32use common_Logger;
33use common_exception_Error;
34use common_session_SessionManager;
35use core_kernel_classes_Resource;
36use oat\generis\model\GenerisRdf;
37use oat\generis\model\OntologyRdf;
38use oat\oatbox\event\EventManager;
39use oat\oatbox\service\ServiceManager;
40use oat\tao\model\event\LogoutSucceedEvent;
41use oat\tao\model\mvc\DefaultUrlService;
42use oat\tao\model\routing\AnnotationReader\security;
43use oat\taoDelivery\helper\Delivery as DeliveryHelper;
44use oat\taoDelivery\model\AssignmentService;
45use oat\taoDelivery\model\execution\DeliveryExecutionConfig;
46use oat\taoDelivery\model\authorization\AuthorizationService;
47use oat\taoDelivery\model\authorization\AuthorizationProvider;
48use oat\taoDelivery\model\execution\DeliveryExecution;
49use oat\taoDelivery\model\execution\DeliveryServerService;
50use oat\taoDelivery\model\execution\ServiceProxy;
51use oat\taoDelivery\model\fields\DeliveryFieldsService;
52use oat\taoDelivery\models\classes\ReturnUrlService;
53use oat\taoDelivery\model\authorization\UnAuthorizedException;
54use oat\tao\helpers\Template;
55use oat\taoDelivery\model\execution\StateServiceInterface;
56use tao_helpers_I18n;
57
58/**
59 * DeliveryServer Controller
60 *
61 * @author CRP Henri Tudor - TAO Team - {@link http://www.tao.lu}
62 * @package taoDelivery
63 * @license GPLv2  http://www.opensource.org/licenses/gpl-2.0.php
64 */
65class DeliveryServer extends \tao_actions_CommonModule
66{
67    private const PROPERTY_INTERFACE_LANGUAGE = 'http://www.tao.lu/Ontologies/TAODelivery.rdf#InterfaceLanguage';
68
69    /**
70     * constructor: initialize the service and the default data
71     * @security("hide")
72     */
73    public function __construct()
74    {
75        $this->service = ServiceManager::getServiceManager()->get(DeliveryServerService::SERVICE_ID);
76    }
77
78    /**
79     * @return DeliveryExecution
80     */
81    protected function getCurrentDeliveryExecution()
82    {
83        $id = \tao_helpers_Uri::decode($this->getRequestParameter('deliveryExecution'));
84        return $this->getExecutionService()->getDeliveryExecution($id);
85    }
86
87    /**
88     * Set a view with the list of process instances (both started or finished) and available process definitions
89     *
90     * @access public
91     * @author CRP Henri Tudor - TAO Team - {@link http://www.tao.lu}
92     * @return void
93     * @throws \common_exception_Error
94     */
95    public function index()
96    {
97        $this->resetOverwrittenLanguage();
98
99        $session = common_session_SessionManager::getSession();
100        $user = $session->getUser();
101
102        /**
103         * Retrieve resumable deliveries (via delivery execution)
104         */
105        $resumableData = [];
106        foreach ($this->getDeliveryServer()->getResumableDeliveries($user) as $de) {
107            $resumableData[] = DeliveryHelper::buildFromDeliveryExecution($de);
108        }
109        $this->setData('resumableDeliveries', $resumableData);
110
111        $assignmentService = $this->getServiceLocator()->get(AssignmentService::SERVICE_ID);
112
113        $deliveryData = [];
114        foreach ($assignmentService->getAssignments($user) as $delivery) {
115            $deliveryData[] = DeliveryHelper::buildFromAssembly($delivery, $user);
116        }
117        $this->setData('availableDeliveries', $deliveryData);
118
119        $this->setTemplate('DeliveryServer/index.tpl', __('TAO: Test Selection'));
120    }
121
122    /**
123     * Get data from request to be passed to renderer
124     * @return array
125     */
126    protected function getViewDataFromRequest()
127    {
128        $lookupParams = ['warning', 'error'];
129        $result = [];
130        foreach ($lookupParams as $lookupParam) {
131            if (
132                $this->getRequest()->hasParameter($lookupParam)
133                && !empty($this->getRequest()->getParameter($lookupParam))
134            ) {
135                $result[] = [
136                    'level' => $lookupParam,
137                    'content' => $this->getRequest()->getParameter($lookupParam),
138                    'timeout' => -1
139                ];
140            }
141        }
142        return $result;
143    }
144
145    /**
146     * Init a delivery execution from the current delivery.
147     *
148     * @throws common_exception_Unauthorized
149     * @return DeliveryExecution the selected execution
150     * @throws \common_exception_Error
151     *
152     * phpcs:disable PSR2.Methods.MethodDeclaration
153     */
154    protected function _initDeliveryExecution()
155    {
156        $compiledDelivery  = new core_kernel_classes_Resource(
157            \tao_helpers_Uri::decode($this->getRequestParameter('uri'))
158        );
159        $user              = common_session_SessionManager::getSession()->getUser();
160
161        $assignmentService = $this->getServiceLocator()->get(AssignmentService::SERVICE_ID);
162
163        $this->verifyDeliveryStartAuthorized($compiledDelivery->getUri());
164
165        //check if the assignment allows the user to start the delivery and the authorization provider
166        if (!$assignmentService->isDeliveryExecutionAllowed($compiledDelivery->getUri(), $user)) {
167            throw new common_exception_Unauthorized();
168        }
169        $stateService = $this->getServiceLocator()->get(StateServiceInterface::SERVICE_ID);
170        /** @var DeliveryExecution $deliveryExecution */
171        $deliveryExecution = $stateService->createDeliveryExecution(
172            $compiledDelivery->getUri(),
173            $user,
174            $compiledDelivery->getLabel()
175        );
176
177        return $deliveryExecution;
178    }
179    // phpcs:enable PSR2.Methods.MethodDeclaration
180
181
182    /**
183     * Init the selected delivery execution and forward to the execution screen
184     */
185    public function initDeliveryExecution(): void
186    {
187        try {
188            $deliveryExecution = $this->_initDeliveryExecution();
189            //if authorized we can move to this URL.
190            $this->redirect(
191                _url(
192                    'runDeliveryExecution',
193                    null,
194                    null,
195                    [
196                        'deliveryExecution' => $deliveryExecution->getIdentifier(),
197                    ]
198                )
199            );
200        } catch (UnAuthorizedException $e) {
201            $this->redirect($e->getErrorPage());
202        } catch (common_exception_Unauthorized $e) {
203            $this->returnJson(
204                [
205                    'success' => false,
206                    'message' => __('You are no longer allowed to take this test')
207                ],
208                403
209            );
210        }
211    }
212
213    /**
214     * Displays the execution screen
215     *
216     * @throws \common_Exception
217     * @throws common_exception_Error
218     * @throws common_exception_NotFound
219     * @throws common_exception_Unauthorized
220     */
221    public function runDeliveryExecution(): void
222    {
223        if ($this->hasGetParameter('waitingPage')) {
224            $this->setData('delivery-execution-url', $this->getGetParameter('deliveryExecutionUrl'));
225            $this->setData('block-title', __('Authorized, you may proceed'));
226            $this->setData('scope', 'waiting-page');
227            $this->setData('hideHomeButton', true);
228            $this->setData('hideLogoutButton', true);
229            $this->setTemplate('DeliveryServer/waiting_page.tpl', __('Waiting page'));
230
231            return;
232        }
233
234        $deliveryExecution = $this->getCurrentDeliveryExecution();
235
236        if (!in_array($deliveryExecution->getState()->getUri(), $this->getDeliveryServer()->getResumableStates())) {
237            $this->redirect($this->getReturnUrl());
238        }
239
240        // Sets the deliveryId to session.
241        if (
242            !$this->hasSessionAttribute(DeliveryExecution::getDeliveryIdSessionKey($deliveryExecution->getIdentifier()))
243        ) {
244            $this->setSessionAttribute(
245                DeliveryExecution::getDeliveryIdSessionKey($deliveryExecution->getIdentifier()),
246                $deliveryExecution->getDelivery()->getUri()
247            );
248        }
249
250        try {
251            $this->verifyDeliveryExecutionAuthorized($deliveryExecution);
252        } catch (UnAuthorizedException $e) {
253            $this->redirect($e->getErrorPage());
254        }
255
256        $userUri = common_session_SessionManager::getSession()->getUserUri();
257        if ($deliveryExecution->getUserIdentifier() != $userUri) {
258            throw new common_exception_Error(
259                'User ' . $userUri . ' is not the owner of the execution ' . $deliveryExecution->getIdentifier()
260            );
261        }
262
263        $delivery = $deliveryExecution->getDelivery();
264
265        $this->initResultServer($delivery, $deliveryExecution->getIdentifier(), $userUri);
266
267        $deliveryExecutionStateService = $this->getServiceManager()->get(StateServiceInterface::SERVICE_ID);
268        $deliveryExecutionStateService->run($deliveryExecution);
269
270        /**
271         * Use particular delivery container
272         */
273        $container = $this->getDeliveryServer()->getDeliveryContainer($deliveryExecution);
274
275        $this->overrideInterfaceLanguage($delivery);
276
277        // Require JS config
278        $container->setData('client_config_url', $this->getClientConfigUrl());
279        $container->setData('client_timeout', $this->getClientTimeout());
280
281        // Delivery params
282        $container->setData('returnUrl', $this->getReturnUrl());
283        $container->setData('finishUrl', $this->getfinishDeliveryExecutionUrl($deliveryExecution));
284
285        $this->setData('additional-header', $container->getContainerHeader());
286        $this->setData('container-body', $container->getContainerBody());
287
288        /** @var DeliveryExecutionConfig $deliveryExecutionConfig */
289        $deliveryExecutionConfig = $this->getServiceLocator()->get(DeliveryExecutionConfig::class);
290
291        /**
292         * Delivery header & footer info
293         */
294        $this->setData('userLabel', common_session_SessionManager::getSession()->getUserLabel());
295        $this->setData('showControls', $this->showControls());
296        $this->setData('hideHomeButton', $deliveryExecutionConfig->isHomeButtonHidden());
297        $this->setData('hideLogoutButton', $deliveryExecutionConfig->isLogoutButtonHidden());
298        $this->setData('returnUrl', $this->getReturnUrl());
299
300        /* @var $urlRouteService DefaultUrlService */
301        $urlRouteService = $this->getServiceManager()->get(DefaultUrlService::SERVICE_ID);
302        $this->setData('logout', $urlRouteService->getUrl('logoutDelivery', []));
303
304        /**
305         * Layout template + real template inclusion
306         */
307        $this->setData('content-template', 'DeliveryServer/runDeliveryExecution.tpl');
308        $this->setData('content-extension', 'taoDelivery');
309        $this->setData('title', $this->getDeliveryFieldsService()->getDeliveryExecutionPageTitle($delivery));
310        $this->setView('DeliveryServer/layout.tpl', 'taoDelivery');
311    }
312
313    /**
314     * Finish the delivery execution
315     *
316     * @throws common_exception_Error
317     * @throws common_exception_NotFound
318     */
319    public function finishDeliveryExecution()
320    {
321        $deliveryExecution = $this->getCurrentDeliveryExecution();
322        if ($deliveryExecution->getUserIdentifier() == common_session_SessionManager::getSession()->getUserUri()) {
323            $stateService = $this->getServiceManager()->get(StateServiceInterface::SERVICE_ID);
324            $stateService->finish($deliveryExecution);
325        } else {
326            common_Logger::w(
327                'Non owner ' . common_session_SessionManager::getSession()->getUserUri()
328                    . ' tried to finish deliveryExecution ' . $deliveryExecution->getIdentifier()
329            );
330        }
331        $this->redirect($this->getReturnUrl());
332    }
333
334    private function setTemplate(string $template, string $title)
335    {
336        $session = common_session_SessionManager::getSession();
337
338        /**
339         * Header & footer info
340         */
341        $this->setData('showControls', $this->showControls());
342        $this->setData('userLabel', tao_helpers_Display::htmlEscape($session->getUserLabel()));
343
344        // Require JS config
345        $this->setData('client_config_url', $this->getClientConfigUrl());
346        $this->setData('client_timeout', $this->getClientTimeout());
347
348        $loaderRenderer = new \Renderer(Template::getTemplate('DeliveryServer/blocks/loader.tpl', 'taoDelivery'));
349        $loaderRenderer->setData('client_config_url', $this->getClientConfigUrl());
350        $loaderRenderer->setData('parameters', ['messages' => $this->getViewDataFromRequest()]);
351
352        /* @var $urlRouteService DefaultUrlService */
353        $urlRouteService = $this->getServiceManager()->get(DefaultUrlService::SERVICE_ID);
354        $this->setData('logout', $urlRouteService->getUrl('logoutDelivery', []));
355
356        /**
357         * Layout template + real template inclusion
358         */
359        $this->setData('additional-header', $loaderRenderer);
360        $this->setData('content-template', $template);
361        $this->setData('content-extension', 'taoDelivery');
362        $this->setData('title', $title);
363        $this->setView('DeliveryServer/layout.tpl', 'taoDelivery');
364    }
365
366    /**
367     * Initialize the result server using the delivery configuration and for this results session submission
368     *
369     * @param $compiledDelivery
370     * @param $executionIdentifier
371     * @param $userUri
372     */
373    protected function initResultServer($compiledDelivery, $executionIdentifier, $userUri)
374    {
375        $this->getDeliveryServer()->initResultServer($compiledDelivery, $executionIdentifier, $userUri);
376    }
377
378    /**
379     * Defines if the top and bottom action menu should be displayed or not
380     *
381     * @return boolean
382     */
383    protected function showControls()
384    {
385        return true;
386    }
387
388    /**
389     * Defines the returning URL in the top-right corner action menu
390     *
391     * @return string
392     * @throws common_exception_NotFound
393     */
394    protected function getReturnUrl()
395    {
396        if ($this->getServiceLocator()->has(ReturnUrlService::SERVICE_ID)) {
397            $deliveryExecution = $this->getCurrentDeliveryExecution();
398
399            return $this
400                ->getServiceLocator()
401                ->get(ReturnUrlService::SERVICE_ID)
402                ->getReturnUrl($deliveryExecution->getIdentifier());
403        }
404        return _url('index', 'DeliveryServer', 'taoDelivery');
405    }
406
407    /**
408     * Defines the URL of the finish delivery execution action
409     * @param DeliveryExecution $deliveryExecution
410     * @return string
411     */
412    protected function getfinishDeliveryExecutionUrl(DeliveryExecution $deliveryExecution)
413    {
414        return _url(
415            'finishDeliveryExecution',
416            null,
417            null,
418            [
419                'deliveryExecution' => $deliveryExecution->getIdentifier(),
420            ]
421        );
422    }
423
424
425    /**
426     * Gives you the authorization provider for the given execution.
427     *
428     * @return AuthorizationProvider
429     */
430    protected function getAuthorizationProvider()
431    {
432        return $this->getServiceLocator()->get(AuthorizationService::SERVICE_ID)->getAuthorizationProvider();
433    }
434
435    /**
436     * Verify if the start of the delivery is allowed.
437     * Throws an exception if not
438     *
439     * @param string $deliveryId
440     * @throws UnAuthorizedException
441     * @throws \common_exception_Error
442     * @throws \common_exception_Unauthorized
443     */
444    protected function verifyDeliveryStartAuthorized($deliveryId)
445    {
446        $user = common_session_SessionManager::getSession()->getUser();
447        $this->getAuthorizationProvider()->verifyStartAuthorization($deliveryId, $user);
448    }
449
450    /**
451     * Check wether the delivery execution is authorized to run
452     * Throws an exception if not
453     *
454     * @param DeliveryExecution $deliveryExecution
455     * @return boolean
456     * @throws \common_exception_Unauthorized
457     * @throws \common_exception_Error
458     * @throws UnAuthorizedException
459     */
460    protected function verifyDeliveryExecutionAuthorized(DeliveryExecution $deliveryExecution): void
461    {
462        $user = common_session_SessionManager::getSession()->getUser();
463        $this->getAuthorizationProvider()->verifyResumeAuthorization($deliveryExecution, $user);
464    }
465
466    public function logout(): void
467    {
468        $eventManager = $this->getServiceLocator()->get(EventManager::SERVICE_ID);
469
470        $logins = common_session_SessionManager::getSession()
471            ->getUser()
472            ->getPropertyValues(GenerisRdf::PROPERTY_USER_LOGIN);
473        $eventManager->trigger(new LogoutSucceedEvent(current($logins)));
474
475        common_session_SessionManager::endSession();
476
477        /* @var $urlRouteService DefaultUrlService */
478        $urlRouteService = $this->getServiceLocator()->get(DefaultUrlService::SERVICE_ID);
479
480        $this->redirect($urlRouteService->getRedirectUrl('logoutDelivery'));
481    }
482
483    protected function getDeliveryServer(): DeliveryServerService
484    {
485        return $this->service = $this->getServiceLocator()->get(DeliveryServerService::SERVICE_ID);
486    }
487
488    protected function getExecutionService(): ServiceProxy
489    {
490        return ServiceProxy::singleton();
491    }
492
493    protected function getDeliveryFieldsService(): DeliveryFieldsService
494    {
495        return $this->getServiceLocator()->get(DeliveryFieldsService::SERVICE_ID);
496    }
497
498    private function overrideInterfaceLanguage(core_kernel_classes_Resource $delivery): void
499    {
500        $deliveryLanguage = $delivery->getProperty(self::PROPERTY_INTERFACE_LANGUAGE);
501
502        if (!$deliveryLanguage->exists()) {
503            $this->resetOverwrittenLanguage();
504
505            return;
506        }
507
508        $deliveryLanguage = $delivery->getOnePropertyValue($deliveryLanguage);
509
510        if (empty($deliveryLanguage)) {
511            $this->resetOverwrittenLanguage();
512
513            return;
514        }
515
516        $resource = $delivery->getResource($deliveryLanguage);
517
518        $language = (string)$resource->getOnePropertyValue(
519            $delivery->getProperty(OntologyRdf::RDF_VALUE)
520        );
521
522        if (empty($language)) {
523            $this->resetOverwrittenLanguage();
524
525            return;
526        }
527
528        $this->setSessionAttribute('overrideInterfaceLanguage', $language);
529
530        tao_helpers_I18n::init(new common_ext_Extension('taoDelivery'), $language);
531    }
532
533    private function resetOverwrittenLanguage(): void
534    {
535        if (!$this->hasSessionAttribute('overrideInterfaceLanguage')) {
536            return;
537        }
538
539        $this->removeSessionAttribute('overrideInterfaceLanguage');
540
541        tao_helpers_I18n::init(
542            new common_ext_Extension('taoDelivery'),
543            common_session_SessionManager::getSession()->getInterfaceLanguage()
544        );
545    }
546}