Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
22.95% |
42 / 183 |
|
16.67% |
3 / 18 |
CRAP | |
0.00% |
0 / 1 |
WorkspaceController | |
22.95% |
42 / 183 |
|
16.67% |
3 / 18 |
1193.52 | |
0.00% |
0 / 1 |
get | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
2 | |||
put | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
patch | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
patchUsers | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
getUsers | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getResults | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
deleteResponses | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
getFile | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
postFile | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
7 | |||
getFiles | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getFilesWithDependencies | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
deleteFiles | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
3 | |||
getReport | |
100.00% |
15 / 15 |
|
100.00% |
1 / 1 |
6 | |||
getSysCheckReportsOverview | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
deleteSysCheckReports | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getSysCheck | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
getSysCheckUnitAndPLayer | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
56 | |||
putSysCheckReport | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | /** @noinspection PhpUnhandledExceptionInspection */ |
4 | declare(strict_types=1); |
5 | |
6 | // TODO unit tests ! |
7 | |
8 | use Slim\Exception\HttpBadRequestException; |
9 | use Slim\Exception\HttpNotFoundException; |
10 | use Slim\Http\Response; |
11 | use Slim\Http\ServerRequest as Request; |
12 | use Slim\Psr7\Stream; |
13 | |
14 | class WorkspaceController extends Controller { |
15 | /** |
16 | * @deprecated |
17 | */ |
18 | public static function get(Request $request, Response $response): Response { |
19 | $workspaceId = (int) $request->getAttribute('ws_id'); |
20 | |
21 | /* @var $authToken AuthToken */ |
22 | $authToken = $request->getAttribute('AuthToken'); |
23 | |
24 | return $response->withJson([ |
25 | "id" => $workspaceId, |
26 | "name" => self::workspaceDAO($workspaceId)->getWorkspaceName(), |
27 | "role" => self::adminDAO()->getWorkspaceRole($authToken->getToken(), $workspaceId) |
28 | ]); |
29 | } |
30 | |
31 | public static function put(Request $request, Response $response): Response { |
32 | $requestBody = JSON::decode($request->getBody()->getContents()); |
33 | if (!isset($requestBody->name)) { |
34 | throw new HttpBadRequestException($request, "New workspace name missing"); |
35 | } |
36 | |
37 | $workspaceCreated = self::superAdminDAO()->createWorkspace($requestBody->name); |
38 | |
39 | $response->getBody()->write(htmlspecialchars($workspaceCreated['id'])); |
40 | return $response->withStatus(201); |
41 | } |
42 | |
43 | public static function patch(Request $request, Response $response): Response { |
44 | $requestBody = JSON::decode($request->getBody()->getContents()); |
45 | $workspaceId = (int) $request->getAttribute('ws_id'); |
46 | |
47 | if (!isset($requestBody->name) or (!$requestBody->name)) { |
48 | throw new HttpBadRequestException($request, "New name (name) is missing"); |
49 | } |
50 | |
51 | self::superAdminDAO()->setWorkspaceName($workspaceId, $requestBody->name); |
52 | |
53 | return $response; |
54 | } |
55 | |
56 | public static function patchUsers(Request $request, Response $response): Response { |
57 | $requestBody = JSON::decode($request->getBody()->getContents()); |
58 | $workspaceId = (int) $request->getAttribute('ws_id'); |
59 | |
60 | if (!isset($requestBody->u) or (!count($requestBody->u))) { |
61 | throw new HttpBadRequestException($request, "User-list (u) is missing"); |
62 | } |
63 | |
64 | self::superAdminDAO()->setUserRightsForWorkspace($workspaceId, $requestBody->u); |
65 | |
66 | return $response->withHeader('Content-type', 'text/plain;charset=UTF-8'); |
67 | } |
68 | |
69 | public static function getUsers(Request $request, Response $response): Response { |
70 | $workspaceId = (int) $request->getAttribute('ws_id'); |
71 | |
72 | return $response->withJson(self::superAdminDAO()->getUsersByWorkspace($workspaceId)); |
73 | } |
74 | |
75 | public static function getResults(Request $request, Response $response): Response { |
76 | $workspaceId = (int) $request->getAttribute('ws_id'); |
77 | $results = self::adminDAO()->getResultStats($workspaceId); |
78 | |
79 | return $response->withJson($results); |
80 | } |
81 | |
82 | public static function deleteResponses(Request $request, Response $response): Response { |
83 | $workspaceId = (int) $request->getAttribute('ws_id'); |
84 | $groups = RequestBodyParser::getRequiredElement($request, 'groups'); |
85 | |
86 | foreach ($groups as $group) { |
87 | self::adminDAO()->deleteResultData($workspaceId, $group); |
88 | } |
89 | |
90 | BroadcastService::send('system/clean'); |
91 | |
92 | return $response; |
93 | } |
94 | |
95 | public static function getFile(Request $request, Response $response): Response { |
96 | $workspaceId = $request->getAttribute('ws_id', 0); |
97 | $fileType = $request->getAttribute('type', '[type missing]'); |
98 | $filename = $request->getAttribute('filename', '[filename missing]'); |
99 | |
100 | $fullFilename = DATA_DIR . "/ws_$workspaceId/$fileType/$filename"; |
101 | if (!file_exists($fullFilename)) { |
102 | throw new HttpNotFoundException($request, "File not found:" . $fullFilename); |
103 | } |
104 | |
105 | $response->withHeader('Content-Description', 'File Transfer'); |
106 | $response->withHeader('Content-Type', ($fileType == 'Resource') ? 'application/octet-stream' : 'text/xml'); |
107 | $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); |
108 | $response->withHeader('Expires', '0'); |
109 | $response->withHeader('Cache-Control', 'must-revalidate'); |
110 | $response->withHeader('Pragma', 'public'); |
111 | $response->withHeader('Content-Length', filesize($fullFilename)); |
112 | |
113 | $fileHandle = fopen($fullFilename, 'rb'); |
114 | |
115 | $fileStream = new Stream($fileHandle); |
116 | |
117 | return $response->withBody($fileStream); |
118 | } |
119 | |
120 | public static function postFile(Request $request, Response $response): Response { |
121 | set_time_limit(600); // because password hashing may take a lot of time if many testtakers are provided |
122 | $workspaceId = (int) $request->getAttribute('ws_id'); |
123 | $workspace = new Workspace($workspaceId); |
124 | |
125 | $filesToImport = UploadedFilesHandler::handleUploadedFiles($request, 'fileforvo', $workspace->getWorkspacePath()); |
126 | |
127 | $importedFilesReports = $workspace->importUncategorizedFiles($filesToImport); |
128 | $workspace->setWorkspaceHash(); |
129 | |
130 | $loginsAffected = false; |
131 | $containsErrors = false; |
132 | foreach ($importedFilesReports as $localPath => $report) { |
133 | $containsErrors = ($containsErrors or !empty($importedFilesReports[$localPath]['error'])); |
134 | $loginsAffected = ($loginsAffected or ($containsErrors and ($importedFilesReports[$localPath]['type'] == 'Testtakers'))); |
135 | $importedFilesReports[$localPath] = array_splice($report, 1); // revert to current structure for output so not to needlessly change the API |
136 | } |
137 | |
138 | if ($loginsAffected) { |
139 | BroadcastService::send('system/clean'); |
140 | } |
141 | |
142 | return $response->withJson($importedFilesReports)->withStatus($containsErrors ? 207 : 201); |
143 | } |
144 | |
145 | public static function getFiles(Request $request, Response $response): Response { |
146 | $workspaceId = (int) $request->getAttribute('ws_id'); |
147 | $workspace = new Workspace($workspaceId); |
148 | |
149 | $files = $workspace->workspaceDAO->getAllFiles(); |
150 | |
151 | // TODo change the FE and endpoint to accept it with keys |
152 | $fileDigestList = []; |
153 | foreach ($files as $fileType => $fileList) { |
154 | $fileDigestList[$fileType] = array_values(File::removeDeprecatedValues($fileList)); |
155 | } |
156 | |
157 | return $response->withJson($fileDigestList); |
158 | } |
159 | |
160 | public static function getFilesWithDependencies(Request $request, Response $response) { |
161 | $workspaceId = (int) $request->getAttribute('ws_id'); |
162 | $names = RequestBodyParser::getRequiredElement($request, 'body'); |
163 | |
164 | $workspace = new Workspace($workspaceId); |
165 | $files = $workspace->workspaceDAO->getFilesByNames($names); |
166 | |
167 | $fileDigestList = []; |
168 | foreach ($files as $fileType => $fileList) { |
169 | $fileDigestList[$fileType] = array_values(File::removeDeprecatedValues($fileList)); |
170 | } |
171 | |
172 | return $response->withJson($fileDigestList); |
173 | } |
174 | |
175 | /** TODO since only allowed files are in the five main folders, a better syntax for the body would suit |
176 | * eg [{"type": "Booklet", "name": "SAMPLE_BOOKLET.XML"}] |
177 | */ |
178 | public static function deleteFiles(Request $request, Response $response): Response { |
179 | $workspaceId = (int) $request->getAttribute('ws_id'); |
180 | $filesToDelete = RequestBodyParser::getRequiredElement($request, 'f'); |
181 | |
182 | $workspace = new Workspace($workspaceId); |
183 | $deletionReport = $workspace->deleteFiles($filesToDelete); |
184 | |
185 | foreach ($deletionReport->deleted as $deletedFile) { |
186 | list($type) = explode('/', $deletedFile); |
187 | if ($type == 'Testtakers') { |
188 | BroadcastService::send('system/clean'); |
189 | self::workspaceDAO($workspaceId)->setSysCheckMode('mixed'); |
190 | break; |
191 | } |
192 | } |
193 | |
194 | $workspace->setWorkspaceHash(); |
195 | |
196 | return $response->withJson($deletionReport)->withStatus(207); |
197 | } |
198 | |
199 | public static function getReport(Request $request, Response $response): ?Response { |
200 | $workspaceId = (int) $request->getAttribute('ws_id'); |
201 | |
202 | $dataIds = $request->getParam('dataIds', '') === '' |
203 | ? [] |
204 | : explode(',', $request->getParam('dataIds', '')); |
205 | |
206 | try { |
207 | $reportType = ReportType::from($request->getAttribute('type')); |
208 | } catch (ValueError $exception) { |
209 | throw new HttpNotFoundException($request, "Report type '{$request->getAttribute('type')}' not found."); |
210 | } |
211 | |
212 | $reportFormat = $request->getHeaderLine('Accept') == 'text/csv' ? ReportFormat::CSV : ReportFormat::JSON; |
213 | |
214 | $report = ReportOutputFactory::createReportOutput($workspaceId, $dataIds, $reportType, $reportFormat); |
215 | |
216 | if ($report->generate($request->getParam('useNewVersion') === 'true')) { |
217 | $response->getBody()->write($report->asString()); |
218 | } |
219 | $response = $reportFormat === ReportFormat::CSV |
220 | ? $response->withHeader('Content-type', 'text/csv;charset=UTF-8') |
221 | : $response->withHeader('Content-Type', 'application/json'); |
222 | |
223 | return $response; |
224 | } |
225 | |
226 | public static function getSysCheckReportsOverview(Request $request, Response $response): Response { |
227 | $workspaceId = (int) $request->getAttribute('ws_id'); |
228 | |
229 | $sysChecksFolder = new SysChecksFolder($workspaceId); |
230 | $reports = $sysChecksFolder->getSysCheckReportList(); |
231 | |
232 | return $response->withJson($reports); |
233 | } |
234 | |
235 | public static function deleteSysCheckReports(Request $request, Response $response): Response { |
236 | $workspaceId = (int) $request->getAttribute('ws_id'); |
237 | $checkIds = RequestBodyParser::getElementWithDefault($request, 'checkIds', []); |
238 | |
239 | $sysChecksFolder = new SysChecksFolder($workspaceId); |
240 | $fileDeletionReport = $sysChecksFolder->deleteSysCheckReports($checkIds); |
241 | |
242 | return $response->withJson($fileDeletionReport)->withStatus(207); |
243 | } |
244 | |
245 | public static function getSysCheck(Request $request, Response $response): Response { |
246 | $workspaceId = (int) $request->getAttribute('ws_id'); |
247 | $sysCheckName = $request->getAttribute('sys-check_name'); |
248 | |
249 | $workspaceController = new Workspace($workspaceId); |
250 | /* @var XMLFileSysCheck $xmlFile */ |
251 | $xmlFile = $workspaceController->getFileById('SysCheck', $sysCheckName); |
252 | |
253 | return $response->withJson([ |
254 | 'name' => $xmlFile->getId(), |
255 | 'label' => $xmlFile->getLabel(), |
256 | 'canSave' => $xmlFile->hasSaveKey(), |
257 | 'hasUnit' => $xmlFile->hasUnit(), |
258 | 'questions' => $xmlFile->getQuestions(), |
259 | 'customTexts' => (object) $xmlFile->getCustomTexts(), |
260 | 'skipNetwork' => $xmlFile->getSkipNetwork(), |
261 | 'downloadSpeed' => $xmlFile->getSpeedtestDownloadParams(), |
262 | 'uploadSpeed' => $xmlFile->getSpeedtestUploadParams(), |
263 | 'workspaceId' => $workspaceId |
264 | ]); |
265 | } |
266 | |
267 | public static function getSysCheckUnitAndPLayer(Request $request, Response $response): Response { |
268 | $workspaceId = (int) $request->getAttribute('ws_id'); |
269 | $sysCheckName = $request->getAttribute('sys-check_name'); |
270 | |
271 | $workspace = new Workspace($workspaceId); |
272 | |
273 | /* @var XMLFileSysCheck $sysCheck */ |
274 | $sysCheck = $workspace->getFileById('SysCheck', $sysCheckName); |
275 | |
276 | $res = [ |
277 | 'player_id' => '', |
278 | 'def' => '', |
279 | 'player' => '' |
280 | ]; |
281 | |
282 | if (!$sysCheck->hasUnit()) { |
283 | return $response->withJson($res); |
284 | } |
285 | |
286 | $unit = $workspace->getFileById('Unit', $sysCheck->getUnitId()); |
287 | /* @var XMLFileUnit $unit */ |
288 | $unitRelations = $workspace->getFileRelations($unit); |
289 | |
290 | foreach ($unitRelations as $unitRelation) { |
291 | /* @var FileRelation $unitRelation */ |
292 | |
293 | switch ($unitRelation->getRelationshipType()) { |
294 | case FileRelationshipType::isDefinedBy: |
295 | |
296 | $unitDefinitionFile = $workspace->getFileByName('Resource', $unitRelation->getTargetName()); |
297 | $res['def'] = $unitDefinitionFile->getContent(); |
298 | break; |
299 | |
300 | case FileRelationshipType::usesPlayer: |
301 | |
302 | $playerFile = $workspace->getFileByName('Resource', $unitRelation->getTargetName()); |
303 | $res['player'] = $playerFile->getContent(); |
304 | $res['player_id'] = $playerFile->getVeronaModuleId(); |
305 | break; |
306 | } |
307 | } |
308 | |
309 | if (!$res['def']) { |
310 | $unitEmbeddedDefinition = $unit->getDefinition(); |
311 | if ($unitEmbeddedDefinition) { |
312 | $res['def'] = $unitEmbeddedDefinition; |
313 | } |
314 | } |
315 | |
316 | return $response->withJson($res); |
317 | } |
318 | |
319 | public static function putSysCheckReport(Request $request, Response $response): Response { |
320 | $workspaceId = (int) $request->getAttribute('ws_id'); |
321 | $sysCheckName = $request->getAttribute('sys-check_name'); |
322 | |
323 | $authToken = $request->getAttribute('AuthToken'); |
324 | $bodyContents = JSON::decode($request->getBody()->getContents()); |
325 | |
326 | $sysChecksFolder = new SysChecksFolder($workspaceId); |
327 | /* @var XMLFileSysCheck $sysCheck */ |
328 | $sysCheck = $sysChecksFolder->getFileById('SysCheck', $sysCheckName); |
329 | |
330 | if ($authToken) { |
331 | $session = self::sessionDAO()->getPersonSessionByToken($authToken->getToken()); |
332 | $bodyContents->title = $session->getLoginSession()->getLogin()->getName(); |
333 | $bodyContents->keyPhrase = ''; |
334 | $report = new SysCheckReport($bodyContents); |
335 | } else { |
336 | $report = new SysCheckReport($bodyContents); |
337 | if (strlen((string) $report->keyPhrase) <= 0) { |
338 | throw new HttpBadRequestException($request, "No key `$report->keyPhrase`"); |
339 | } |
340 | |
341 | if (strtoupper((string) $report->keyPhrase) !== strtoupper($sysCheck->getSaveKey())) { |
342 | throw new HttpError("Wrong key `$report->keyPhrase`", 403); |
343 | } |
344 | } |
345 | |
346 | $report->checkId = $sysCheck->getId(); |
347 | $report->checkLabel = $sysCheck->getLabel(); |
348 | |
349 | $sysChecksFolder->saveSysCheckReport($report); |
350 | |
351 | return $response->withStatus(201); |
352 | } |
353 | } |