ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
AccessFileUploadAnswer.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26use ilObjTest;
27use ilObject;
28use ilSession;
30use ilTestAccess;
32use ilObjUser;
33use Closure;
34
36{
38 private readonly Closure $object_id_of_test_id;
40 private readonly Closure $references_of;
42 private readonly Closure $session;
44 private readonly Closure $checkResultsAccess;
45 private readonly Incident $incident;
46
53 public function __construct(
54 private readonly ilObjUser $user,
55 private readonly ilDBInterface $database,
56 private readonly Readable $readable,
57 $object_id_of_test_id = [ilObjTest::class, '_getObjectIDFromTestID'],
58 $references_of = [ilObject::class, '_getAllReferences'],
59 $session = [ilSession::class, 'get'],
60 ?callable $checkResultsAccess = null,
61 ?Incident $incident = null
62 ) {
63 $this->incident = $incident ?? new Incident();
64 $this->object_id_of_test_id = Closure::fromCallable($object_id_of_test_id);
65 $this->references_of = Closure::fromCallable($references_of);
66 $this->session = Closure::fromCallable($session);
67 $checkResultsAccess = $checkResultsAccess ?? static function (int $reference, int $test_id, int $active_id): bool {
68 $access = new ilTestAccess($reference);
69 return $access->checkResultsAccessForActiveId($active_id, $test_id);
70 };
71 $this->checkResultsAccess = Closure::fromCallable($checkResultsAccess);
72 }
73
74 public function isPermitted(string $path): Result
75 {
76 $path_and_test = $this->pathAndTestId($path);
77
78 if (!$path_and_test) {
79 return new Error('Not a file upload path of test answers.');
80 }
81 if (!$path_and_test['test']) {
82 return new Ok(false);
83 }
84
85 $object_id = (int) ($this->object_id_of_test_id)($path_and_test['test']);
86 if (!$object_id) {
87 return new Ok(false);
88 }
89
90 $references = ($this->references_of)($object_id);
91
92 return new Ok($this->readable->references($references) && $this->roleBasedCheck($path_and_test['test'], $references, $path_and_test['path']));
93 }
94
95 private function isAnonymous(): bool
96 {
97 return $this->user->isAnonymous() || !$this->user->getId();
98 }
99
100 private function accessCodeOk(string $file, int $test_id): bool
101 {
102 $code = ($this->session)(ilTestSession::ACCESS_CODE_SESSION_INDEX)[$test_id] ?? false;
103
104 return $code && $this->userDidUpload($test_id, $file, $code);
105 }
106
107 private function userDidUpload(int $test_id, string $file, ?string $code = null): bool
108 {
109 $where = [
110 'active_id = active_fi',
111 'user_fi = %s',
112 'value1 = %s',
113 'anonymous_id ' . (null === $code ? 'IS' : '=') . ' %s',
114 'test_fi = %s',
115 ];
116
117 $result = $this->database->queryF(
118 'SELECT 1 FROM tst_solutions WHERE EXISTS (SELECT 1 FROM tst_active WHERE ' . implode(' AND ', $where) . ')',
119 ['integer', 'text', 'text', 'integer'],
120 [$this->user->getId(), $file, $code, $test_id]
121 );
122
123 return (bool) $this->database->numRows($result);
124 }
125
126 private function activeIdOfFile(string $file, int $test): ?int
127 {
128 $is_upload_question = 'EXISTS (SELECT 1 FROM qpl_qst_type INNER JOIN qpl_questions ON question_type_id = question_type_fi WHERE type_tag = %s AND tst_solutions.question_fi = qpl_questions.question_id)';
129 $is_in_test = 'EXISTS (SELECT 1 FROM tst_active WHERE test_fi = %s AND active_id = active_fi)';
130
131 $result = $this->database->queryF(
132 "SELECT active_fi, value1 FROM tst_solutions WHERE $is_upload_question AND $is_in_test",
133 ['text', 'integer'],
134 ['assFileUpload', $test]
135 );
136
137 while (($row = $this->database->fetchAssoc($result))) {
138 if ($row['value1'] === $file) {
139 return (int) $row['active_fi'];
140 }
141 }
142
143 return null;
144 }
145
153 private function roleBasedCheck(int $test_id, array $references, string $file): bool
154 {
155 return $this->isAnonymous() ? $this->accessCodeOk($file, $test_id) : $this->canAccessResults($test_id, $references, $file) || $this->userDidUpload($test_id, $file);
156 }
157
165 private function canAccessResults(int $test_id, array $references, string $file): bool
166 {
167 $active_id = $this->activeIdOfFile($file, $test_id);
168 if (!$active_id) {
169 return false;
170 }
171
172 return $this->incident->any(fn(int $reference): bool => (
173 ($this->checkResultsAccess)($reference, $test_id, $active_id)
174 ), $references);
175 }
176
182 private function pathAndTestId(string $path): ?array
183 {
184 $results = [];
185 if (!preg_match(':/assessment/tst_(\d+)/.*/([^/]+)$:', $path, $results)) {
186 return null;
187 }
188
189 return [
190 'test' => (int) $results[1],
191 'path' => $results[2],
192 ];
193 }
194}
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Ok.php:31
roleBasedCheck(int $test_id, array $references, string $file)
userDidUpload(int $test_id, string $file, ?string $code=null)
canAccessResults(int $test_id, array $references, string $file)
__construct(private readonly ilObjUser $user, private readonly ilDBInterface $database, private readonly Readable $readable, $object_id_of_test_id=[ilObjTest::class, '_getObjectIDFromTestID'], $references_of=[ilObject::class, '_getAllReferences'], $session=[ilSession::class, 'get'], ?callable $checkResultsAccess=null, ?Incident $incident=null)
User class.
Class ilObject Basic functions for all objects.
Test session handler.
A result encapsulates a value or an error and simplifies the handling of those.
Definition: Result.php:29
Interface ilDBInterface.
$path
Definition: ltiservices.php:30
$results