Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 136
0.00% covered (danger)
0.00%
0 / 16
CRAP
0.00% covered (danger)
0.00%
0 / 1
taoTests_actions_Tests
0.00% covered (danger)
0.00%
0 / 136
0.00% covered (danger)
0.00%
0 / 16
1190
0.00% covered (danger)
0.00%
0 / 1
 getEventManager
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getClassService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 preview
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 editTest
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 1
110
 delete
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
42
 authoring
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 moveInstance
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 moveAll
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 cloneInstance
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 deleteAll
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 moveClass
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDependsOnPropertyValidator
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getClassDeleter
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getResourceDeleter
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getTranslationSyncService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3// phpcs:disable Generic.Files.LineLength
4/*
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; under version 2
8 * of the License (non-upgradable).
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 *
19 * Copyright (c) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg (under the project TAO & TAO2);
20 *               2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
21 *               2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
22 *
23 */
24// phpcs:enable
25
26use oat\oatbox\event\EventManager;
27use oat\tao\model\lock\LockManager;
28use oat\oatbox\validator\ValidatorInterface;
29use oat\tao\model\accessControl\Context;
30use oat\tao\model\resources\ResourceWatcher;
31use oat\tao\model\TaoOntology;
32use oat\taoTests\models\event\TestUpdatedEvent;
33use oat\tao\model\controller\SignedFormInstance;
34use oat\tao\model\resources\Service\ClassDeleter;
35use oat\tao\model\routing\AnnotationReader\security;
36use oat\taoTests\models\Form\Modifier\FormModifierProxy;
37use oat\taoTests\models\Translation\Form\Modifier\TranslationFormModifierProxy;
38use tao_helpers_form_FormContainer as FormContainer;
39use oat\generis\model\resource\Service\ResourceDeleter;
40use oat\tao\model\resources\Contract\ClassDeleterInterface;
41use oat\generis\model\resource\Contract\ResourceDeleterInterface;
42use oat\generis\model\resource\exception\ResourceDeletionException;
43use oat\tao\model\resources\Exception\PartialClassDeletionException;
44use oat\tao\model\Lists\Business\Validation\DependsOnPropertyValidator;
45use oat\tao\model\Translation\Service\TranslationSyncService;
46
47/**
48 * Tests Controller provide actions performed from url resolution
49 *
50 * @author Bertrand Chevrier, <taosupport@tudor.lu>
51 * @package taoTests
52
53 * @license GPLv2  http://www.opensource.org/licenses/gpl-2.0.php
54 *
55 */
56// phpcs:ignore
57class taoTests_actions_Tests extends tao_actions_SaSModule
58{
59    /**
60     * @return EventManager
61     */
62    protected function getEventManager()
63    {
64        return $this->getServiceLocator()->get(EventManager::SERVICE_ID);
65    }
66
67    protected function getClassService()
68    {
69        return taoTests_models_classes_TestsService::singleton();
70    }
71
72    /**
73     * constructor: initialize the service and the default data
74     * @security("hide")
75     */
76    public function __construct()
77    {
78        parent::__construct();
79
80        //the service is initialized by default
81        $this->service = taoTests_models_classes_TestsService::singleton();
82        $this->defaultData();
83    }
84
85    /*
86    * controller actions
87    */
88
89    /**
90     * @requiresRight id READ
91     */
92    public function preview(): void
93    {
94        $this->index();
95    }
96
97    /**
98     * edit a test instance
99     * @requiresRight id READ
100     */
101    public function editTest()
102    {
103        $test = new core_kernel_classes_Resource($this->getRequestParameter('id'));
104
105        $this->setData('isPreviewEnabled', $this->service->hasItems($test));
106
107        if (!$this->isLocked($test)) {
108            // my lock
109            $lock = LockManager::getImplementation()->getLockData($test);
110            $sessionIdentifier = common_session_SessionManager::getSession()->getUser()->getIdentifier();
111
112            if (!is_null($lock) && $lock->getOwnerId() === $sessionIdentifier) {
113                $this->setData('lockDate', $lock->getCreationTime());
114                $this->setData('id', $lock->getResource()->getUri());
115            }
116
117            $context = new Context(
118                [
119                    Context::PARAM_CONTROLLER => self::class,
120                    Context::PARAM_ACTION => __FUNCTION__,
121                ]
122            );
123            $hasWriteAccess = $this->hasWriteAccess($test->getUri()) && $this->hasWriteAccessByContext($context);
124
125            $clazz = $this->getCurrentClass();
126            $formContainer = new SignedFormInstance(
127                $clazz,
128                $test,
129                [
130                    FormContainer::IS_DISABLED => !$hasWriteAccess,
131                    FormContainer::CSRF_PROTECTION_OPTION => true,
132                    FormContainer::ATTRIBUTE_VALIDATORS => [
133                        'data-depends-on-property' => [
134                            $this->getDependsOnPropertyValidator(),
135                        ],
136                    ],
137                    FormContainer::FORM_MODIFIERS => [
138                        FormModifierProxy::class,
139                        TranslationFormModifierProxy::class,
140                    ],
141                ]
142            );
143            $myForm = $formContainer->getForm();
144
145            $myForm->setOptions([
146                'resourceType' => TaoOntology::CLASS_URI_TEST
147            ]);
148
149            if ($hasWriteAccess) {
150                if ($myForm->isSubmited() && $myForm->isValid()) {
151                    $this->validateInstanceRoot($test->getUri());
152
153                    $propertyValues = $myForm->getValues();
154
155                    // don't hande the testmodel via bindProperties
156                    if (
157                        array_key_exists(
158                            taoTests_models_classes_TestsService::PROPERTY_TEST_TESTMODEL,
159                            $propertyValues
160                        )
161                    ) {
162                        $modelUri = $propertyValues[taoTests_models_classes_TestsService::PROPERTY_TEST_TESTMODEL];
163                        unset($propertyValues[taoTests_models_classes_TestsService::PROPERTY_TEST_TESTMODEL]);
164                        if (!empty($modelUri)) {
165                            $testModel = new core_kernel_classes_Resource($modelUri);
166                            $this->service->setTestModel($test, $testModel);
167                        }
168                    } else {
169                        common_Logger::w('No testmodel on test form', 'taoTests');
170                    }
171
172                    //then save the property values as usual
173                    $binder = new tao_models_classes_dataBinding_GenerisFormDataBinder($test);
174                    $test = $binder->bind($propertyValues);
175                    $this->getEventManager()->trigger(new TestUpdatedEvent($test->getUri(), $propertyValues));
176
177                    $this->setData('selectNode', tao_helpers_Uri::encode($test->getUri()));
178                    $this->setData('message', __('Test saved'));
179                    $this->setData('reload', true);
180                }
181            } else {
182                $myForm->setActions([]);
183            }
184
185            $myForm->removeElement(tao_helpers_Uri::encode(
186                taoTests_models_classes_TestsService::PROPERTY_TEST_CONTENT
187            ));
188            $updatedAt = $this->getServiceLocator()->get(ResourceWatcher::SERVICE_ID)->getUpdatedAt($test);
189            $this->setData('updatedAt', $updatedAt);
190            $this->setData('uri', tao_helpers_Uri::encode($test->getUri()));
191            $this->setData('classUri', tao_helpers_Uri::encode($clazz->getUri()));
192            $this->setData('formTitle', __('Test properties'));
193            $this->setData('myForm', $myForm->render());
194            $this->setView('Tests/editTest.tpl');
195        }
196    }
197
198    /**
199     * delete a test or a test class. called via ajax
200     *
201     * @throws Exception
202     * @throws common_exception_BadRequest
203     * @requiresRight id WRITE
204     */
205    public function delete()
206    {
207        try {
208            $this->validateCsrf();
209        } catch (common_exception_Unauthorized $e) {
210            $this->response = $this->getPsrResponse()->withStatus(403, __('Unable to process your request'));
211            return;
212        }
213        if (!tao_helpers_Request::isAjax()) {
214            throw new common_exception_BadRequest('wrong request mode');
215        }
216
217        $uri = $this->getRequestParameter('id');
218
219        $this->validateInstanceRoot($uri);
220
221        $instance = $this->getCurrentInstance('id');
222
223        $lockManager = LockManager::getImplementation();
224        $userId = common_session_SessionManager::getSession()->getUser()->getIdentifier();
225
226        if ($lockManager->isLocked($instance)) {
227            $lockManager->releaseLock($instance, $userId);
228        }
229
230        $label = $instance->getLabel();
231        /**
232         * @var ResourceDeleterInterface|ClassDeleterInterface $deleter
233         * @var core_kernel_classes_Resource|core_kernel_classes_Class $instanceToDelete
234         */
235        [$deleter, $instanceToDelete] = $instance->isClass()
236            ? [$this->getClassDeleter(), $this->getClass($instance)]
237            : [$this->getResourceDeleter(), $instance];
238
239        try {
240            $deleter->delete($instanceToDelete);
241            $success = true;
242            $deleted = true;
243            $message = __('%s has been deleted', $label);
244        } catch (PartialClassDeletionException | ResourceDeletionException $exception) {
245            $success = $exception instanceof PartialClassDeletionException;
246            $deleted = false;
247            $message = $exception->getUserMessage();
248        }
249
250        $this->returnJson([
251            'success' => $success,
252            'message' => $message,
253            'deleted' => $deleted,
254        ]);
255    }
256
257    /**
258     * Redirect the test's authoring
259     * @requiresRight id WRITE
260     */
261    public function authoring()
262    {
263        $test = new core_kernel_classes_Resource($this->getRequestParameter('id'));
264        if (!$this->isLocked($test)) {
265            $testModel = $this->service->getTestModel($test);
266            $testModelImpl = $this->service->getTestModelImplementation($testModel);
267            $authoringUrl = $testModelImpl->getAuthoringUrl($test);
268            if (!empty($authoringUrl)) {
269                $userId = common_session_SessionManager::getSession()->getUser()->getIdentifier();
270                LockManager::getImplementation()->setLock($test, $userId);
271
272                // Add support for the translation and the side-by-side authoring tool
273                if ($this->getRequestParameter('translation') !== null) {
274                    $authoringUrl = sprintf(
275                        '%s&translation=%s',
276                        $authoringUrl,
277                        $this->getRequestParameter('translation')
278                    );
279                }
280                if ($this->getRequestParameter('originResourceUri') !== null) {
281                    $this->getTranslationSyncService()->syncById($this->getRequestParameter('originResourceUri'));
282                    $authoringUrl = sprintf(
283                        '%s&originResourceUri=%s',
284                        $authoringUrl,
285                        $this->getRequestParameter('originResourceUri')
286                    );
287                }
288
289                return $this->forwardUrl($authoringUrl);
290            }
291            throw new common_exception_NoImplementation();
292        }
293    }
294
295    /**
296     * overwrite the parent moveInstance to add the requiresRight only in Tests
297     * @see tao_actions_TaoModule::moveInstance()
298     * @requiresRight uri WRITE
299     * @requiresRight destinationClassUri WRITE
300     */
301    public function moveInstance()
302    {
303        parent::moveInstance();
304    }
305
306    /**
307     * overwrite the parent moveAllInstances to add the requiresRight only in Items
308     * @see tao_actions_TaoModule::moveAll()
309     * @requiresRight ids WRITE
310     */
311    public function moveAll()
312    {
313        return parent::moveAll();
314    }
315
316    /**
317     * overwrite the parent cloneInstance to add the requiresRight only in Tests
318     * @see tao_actions_TaoModule::cloneInstance()
319     * @requiresRight uri READ
320     * @requiresRight classUri WRITE
321     */
322    public function cloneInstance()
323    {
324        return parent::cloneInstance();
325    }
326
327    /**
328     * Delete all given resources
329     *
330     * @requiresRight ids WRITE
331     *
332     * @throws Exception
333     */
334    public function deleteAll()
335    {
336        return parent::deleteAll();
337    }
338
339    /**
340     * Move class to another location
341     * @requiresRight classUri WRITE
342     */
343    public function moveClass()
344    {
345        return parent::moveResource();
346    }
347
348    private function getDependsOnPropertyValidator(): ValidatorInterface
349    {
350        return $this->getPsrContainer()->get(DependsOnPropertyValidator::class);
351    }
352
353    private function getClassDeleter(): ClassDeleterInterface
354    {
355        return $this->getPsrContainer()->get(ClassDeleter::class);
356    }
357
358    private function getResourceDeleter(): ResourceDeleterInterface
359    {
360        return $this->getPsrContainer()->get(ResourceDeleter::class);
361    }
362
363    private function getTranslationSyncService(): TranslationSyncService
364    {
365        return $this->getPsrContainer()->get(TranslationSyncService::class);
366    }
367}