Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractRestQti
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 11
812
0.00% covered (danger)
0.00%
0 / 1
 getTaskName
n/a
0 / 0
n/a
0 / 0
0
 getStatus
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
12
 getTaskStatus
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 isMetadataGuardiansEnabled
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 isMetadataValidatorsEnabled
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 isMetadataRequired
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 isItemMustExistEnabled
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 isItemMustBeOverwrittenEnabled
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
12
 updateMetadata
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 getUpdateMetadataRequestHandler
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getMetadataService
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getQueryParams
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
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) 2017-2025 (original work) Open Assessment Technologies SA;
19 *
20 *
21 */
22
23namespace oat\taoQtiItem\controller;
24
25use tao_actions_RestController;
26use common_exception_MethodNotAllowed as HttpMethodNotAllowedException;
27use common_exception_RestApi as BadRequestException;
28use InvalidArgumentException;
29use JsonException;
30use oat\tao\model\http\HttpJsonResponseTrait;
31use oat\tao\model\taskQueue\TaskLog\Entity\EntityInterface;
32use oat\tao\model\taskQueue\TaskLogActionTrait;
33use oat\taoQtiItem\model\presentation\web\UpdateMetadataRequestHandler;
34use oat\taoQtiItem\model\qti\metadata\MetadataService;
35use Request;
36use RuntimeException;
37use common_exception_MissingParameter;
38use Exception;
39
40/**
41 * Class AbstractRestQti
42 * @package oat\taoQtiItem\controller
43 * @author Aleh Hutnikau, <hutnikau@1pt.com>
44 * @author Gyula Szucs <gyula@taotesting.com>
45 */
46abstract class AbstractRestQti extends tao_actions_RestController
47{
48    use TaskLogActionTrait;
49    use HttpJsonResponseTrait;
50
51    public const TASK_ID_PARAM = 'id';
52
53    public const ENABLE_METADATA_GUARDIANS = 'enableMetadataGuardians';
54
55    public const ENABLE_METADATA_VALIDATORS = 'enableMetadataValidators';
56
57    public const METADATA_REQUIRED = 'metadataRequired';
58
59    public const ITEM_MUST_EXIST = 'itemMustExist';
60
61    public const ITEM_MUST_BE_OVERWRITTEN = 'itemMustBeOverwritten';
62
63    protected static $accepted_types = [
64        'application/zip',
65        'application/x-zip-compressed',
66        'multipart/x-zip',
67        'application/x-compressed'
68    ];
69
70    /**
71     * Name of the task created by the child.
72     *
73     * @return string
74     */
75    abstract protected function getTaskName();
76
77    /**
78     * Action to retrieve test import status from queue
79     */
80    public function getStatus(): void
81    {
82        try {
83            if (!$this->getQueryParams(self::TASK_ID_PARAM)) {
84                throw new common_exception_MissingParameter(self::TASK_ID_PARAM, $this->getRequestURI());
85            }
86
87            $data = $this->getTaskLogReturnData(
88                $this->getQueryParams(self::TASK_ID_PARAM),
89                $this->getTaskName()
90            );
91
92            $this->setSuccessJsonResponse($data);
93        } catch (Exception $e) {
94            $this->returnFailure($e);
95        }
96    }
97
98    /**
99     * Return 'Success' instead of 'Completed', required by the specified API.
100     *
101     * @param EntityInterface $taskLogEntity
102     */
103    protected function getTaskStatus(EntityInterface $taskLogEntity): string
104    {
105        if ($taskLogEntity->getStatus()->isCreated()) {
106            return __('In Progress');
107        } elseif ($taskLogEntity->getStatus()->isCompleted()) {
108            return __('Success');
109        }
110
111        return $taskLogEntity->getStatus()->getLabel();
112    }
113
114    protected function isMetadataGuardiansEnabled(): bool
115    {
116        $enableMetadataGuardians = $this->getQueryParams(self::ENABLE_METADATA_GUARDIANS);
117
118        if (is_null($enableMetadataGuardians)) {
119            return true; // default value if parameter not passed
120        }
121
122        if (!in_array($enableMetadataGuardians, ['true', 'false'])) {
123            throw new BadRequestException(
124                self::ENABLE_METADATA_GUARDIANS . ' parameter should be boolean (true or false).'
125            );
126        }
127
128        return filter_var($enableMetadataGuardians, FILTER_VALIDATE_BOOLEAN);
129    }
130
131    protected function isMetadataValidatorsEnabled(): bool
132    {
133        $enableMetadataValidators = $this->getQueryParams(self::ENABLE_METADATA_VALIDATORS);
134
135        if (is_null($enableMetadataValidators)) {
136            return true; // default value if parameter not passed
137        }
138
139        if (!in_array($enableMetadataValidators, ['true', 'false'])) {
140            throw new BadRequestException(
141                self::ENABLE_METADATA_VALIDATORS . ' parameter should be boolean (true or false).'
142            );
143        }
144
145        return filter_var($enableMetadataValidators, FILTER_VALIDATE_BOOLEAN);
146    }
147
148    protected function isMetadataRequired(): bool
149    {
150        $metadataRequired = $this->getQueryParams(self::METADATA_REQUIRED);
151
152        if (is_null($metadataRequired)) {
153            return false; // default value if parameter not passed
154        }
155
156        if (!in_array($metadataRequired, ['true', 'false'])) {
157            throw new BadRequestException(
158                self::ENABLE_METADATA_VALIDATORS . ' parameter should be boolean (true or false).'
159            );
160        }
161
162        return filter_var($metadataRequired, FILTER_VALIDATE_BOOLEAN);
163    }
164
165    protected function isItemMustExistEnabled(): bool
166    {
167        $itemMustExistEnabled = $this->getQueryParams(self::ITEM_MUST_EXIST);
168
169        if (is_null($itemMustExistEnabled)) {
170            return false; // default value if parameter not passed
171        }
172
173        if (!in_array($itemMustExistEnabled, ['true', 'false'])) {
174            throw new BadRequestException(
175                self::ITEM_MUST_EXIST . ' parameter should be boolean (true or false).'
176            );
177        }
178
179        return filter_var($itemMustExistEnabled, FILTER_VALIDATE_BOOLEAN);
180    }
181
182    protected function isItemMustBeOverwrittenEnabled(): bool
183    {
184        $isItemMustBeOverwrittenEnabled = $this->getQueryParams(self::ITEM_MUST_BE_OVERWRITTEN);
185
186        if (is_null($isItemMustBeOverwrittenEnabled)) {
187            return false; // default value if parameter not passed
188        }
189
190        if (!in_array($isItemMustBeOverwrittenEnabled, ['true', 'false'])) {
191            throw new BadRequestException(
192                self::ITEM_MUST_BE_OVERWRITTEN . ' parameter should be boolean (true or false).'
193            );
194        }
195
196        return filter_var($isItemMustBeOverwrittenEnabled, FILTER_VALIDATE_BOOLEAN);
197    }
198
199    /**
200     * Update metadata by parameters
201     */
202    public function updateMetadata(): void
203    {
204        if ($this->getRequestMethod() !== Request::HTTP_POST) {
205            throw new HttpMethodNotAllowedException(null, 0, [Request::HTTP_POST]);
206        }
207
208        try {
209            $metadataInput = $this->getUpdateMetadataRequestHandler()->handle(
210                $this->getPsrRequest()
211            );
212
213            $resourceIdentifier = $metadataInput->getResource()->getUri();
214
215            $this->getMetadataService()->getImporter()->setMetadataValues(
216                [$resourceIdentifier => [$metadataInput->getMetadata()]]
217            );
218
219            $this->getMetadataService()->getImporter()->inject(
220                $resourceIdentifier,
221                $metadataInput->getResource()
222            );
223        } catch (JsonException | InvalidArgumentException $exception) {
224            throw new BadRequestException($exception->getMessage(), 400);
225        } catch (RuntimeException $exception) {
226            throw new BadRequestException($exception->getMessage(), 422);
227        }
228
229        $this->setSuccessJsonResponse($metadataInput);
230    }
231
232    private function getUpdateMetadataRequestHandler(): UpdateMetadataRequestHandler
233    {
234        return $this->getPsrContainer()->get(UpdateMetadataRequestHandler::class);
235    }
236
237    private function getMetadataService(): MetadataService
238    {
239        return $this->getPsrContainer()->get(MetadataService::SERVICE_ID);
240    }
241
242    protected function getQueryParams($key): mixed
243    {
244        $body = $this->getPsrRequest()->getParsedBody();
245        $query = $this->getPsrRequest()->getQueryParams();
246        $uploadedFiles = $this->getPsrRequest()->getUploadedFiles();
247        $params = array_merge($body, $query, $uploadedFiles);
248        return $params[$key] ?? null;
249    }
250}