Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 136 |
|
0.00% |
0 / 16 |
CRAP | |
0.00% |
0 / 1 |
| taoTests_actions_Tests | |
0.00% |
0 / 136 |
|
0.00% |
0 / 16 |
1190 | |
0.00% |
0 / 1 |
| getEventManager | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getClassService | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| __construct | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| preview | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| editTest | |
0.00% |
0 / 68 |
|
0.00% |
0 / 1 |
110 | |||
| delete | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
42 | |||
| authoring | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
30 | |||
| moveInstance | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| moveAll | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| cloneInstance | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| deleteAll | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| moveClass | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getDependsOnPropertyValidator | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getClassDeleter | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getResourceDeleter | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getTranslationSyncService | |
0.00% |
0 / 1 |
|
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 | |
| 26 | use oat\oatbox\event\EventManager; |
| 27 | use oat\tao\model\lock\LockManager; |
| 28 | use oat\oatbox\validator\ValidatorInterface; |
| 29 | use oat\tao\model\accessControl\Context; |
| 30 | use oat\tao\model\resources\ResourceWatcher; |
| 31 | use oat\tao\model\TaoOntology; |
| 32 | use oat\taoTests\models\event\TestUpdatedEvent; |
| 33 | use oat\tao\model\controller\SignedFormInstance; |
| 34 | use oat\tao\model\resources\Service\ClassDeleter; |
| 35 | use oat\tao\model\routing\AnnotationReader\security; |
| 36 | use oat\taoTests\models\Form\Modifier\FormModifierProxy; |
| 37 | use oat\taoTests\models\Translation\Form\Modifier\TranslationFormModifierProxy; |
| 38 | use tao_helpers_form_FormContainer as FormContainer; |
| 39 | use oat\generis\model\resource\Service\ResourceDeleter; |
| 40 | use oat\tao\model\resources\Contract\ClassDeleterInterface; |
| 41 | use oat\generis\model\resource\Contract\ResourceDeleterInterface; |
| 42 | use oat\generis\model\resource\exception\ResourceDeletionException; |
| 43 | use oat\tao\model\resources\Exception\PartialClassDeletionException; |
| 44 | use oat\tao\model\Lists\Business\Validation\DependsOnPropertyValidator; |
| 45 | use 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 |
| 57 | class 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 | } |