Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 136 |
|
0.00% |
0 / 17 |
CRAP | |
0.00% |
0 / 1 |
GroupAssignment | |
0.00% |
0 / 136 |
|
0.00% |
0 / 17 |
2450 | |
0.00% |
0 / 1 |
getAssignments | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getAssignmentFactories | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
72 | |||
getRuntime | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getAssignedUsers | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
12 | |||
onDelete | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
getDeliveryIdsByUser | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
30 | |||
isUserExcluded | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getGuestAccessDeliveries | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
isDeliveryGuestUser | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isDeliveryExecutionAllowed | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
12 | |||
verifyUserAssigned | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
20 | |||
hasDeliveryGuestAccess | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
20 | |||
verifyToken | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
20 | |||
verifyTime | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
20 | |||
areWeInRange | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
20 | |||
orderAssignments | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getAssignmentFactory | |
0.00% |
0 / 3 |
|
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) 2015 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); |
19 | * |
20 | */ |
21 | |
22 | namespace oat\taoDeliveryRdf\model; |
23 | |
24 | use oat\taoGroups\models\GroupsService; |
25 | use oat\oatbox\user\User; |
26 | use oat\oatbox\service\ConfigurableService; |
27 | use core_kernel_classes_Resource; |
28 | use core_kernel_classes_Class; |
29 | use core_kernel_classes_Property; |
30 | use oat\taoDelivery\model\AssignmentService; |
31 | use oat\taoDeliveryRdf\model\guest\GuestTestUser; |
32 | use oat\taoDelivery\model\RuntimeService; |
33 | use oat\taoDelivery\model\AttemptServiceInterface; |
34 | |
35 | /** |
36 | * Service to manage the assignment of users to deliveries |
37 | * |
38 | * @access public |
39 | * @author Joel Bout, <joel@taotesting.com> |
40 | * @package taoDelivery |
41 | */ |
42 | class GroupAssignment extends ConfigurableService implements AssignmentService |
43 | { |
44 | /** |
45 | * Interface part |
46 | */ |
47 | public const PROPERTY_GROUP_DELIVERY = 'http://www.tao.lu/Ontologies/TAOGroup.rdf#Deliveries'; |
48 | |
49 | public const DISPLAY_ATTEMPTS_OPTION = 'display_attempts'; |
50 | |
51 | public const DISPLAY_DATES_OPTION = 'display_dates'; |
52 | |
53 | /** |
54 | * (non-PHPdoc) |
55 | * @see \oat\taoDelivery\model\AssignmentService::getAssignments() |
56 | */ |
57 | public function getAssignments(User $user) |
58 | { |
59 | $assignments = []; |
60 | foreach ($this->getAssignmentFactories($user) as $factory) { |
61 | $assignments[] = $factory->toAssignment(); |
62 | } |
63 | |
64 | return $this->orderAssignments($assignments); |
65 | } |
66 | |
67 | /** |
68 | * @param User $user |
69 | * @return array |
70 | */ |
71 | public function getAssignmentFactories(User $user) |
72 | { |
73 | $assignments = []; |
74 | |
75 | $displayAttempts = ($this->hasOption(self::DISPLAY_ATTEMPTS_OPTION)) |
76 | ? $this->getOption(self::DISPLAY_ATTEMPTS_OPTION) |
77 | : true; |
78 | |
79 | $displayDates = ($this->hasOption(self::DISPLAY_DATES_OPTION)) |
80 | ? $this->getOption(self::DISPLAY_DATES_OPTION) |
81 | : true; |
82 | |
83 | if ($this->isDeliveryGuestUser($user)) { |
84 | foreach ($this->getGuestAccessDeliveries() as $id) { |
85 | $delivery = new \core_kernel_classes_Resource($id); |
86 | $startable = $this->verifyTime($delivery) && $this->verifyToken($delivery, $user); |
87 | $assignments[] = $this->getAssignmentFactory( |
88 | $delivery, |
89 | $user, |
90 | $startable, |
91 | $displayAttempts, |
92 | $displayDates |
93 | ); |
94 | } |
95 | } else { |
96 | foreach ($this->getDeliveryIdsByUser($user) as $id) { |
97 | $delivery = new \core_kernel_classes_Resource($id); |
98 | $startable = $this->verifyTime($delivery) && $this->verifyToken($delivery, $user); |
99 | $assignments[] = $this->getAssignmentFactory( |
100 | $delivery, |
101 | $user, |
102 | $startable, |
103 | $displayAttempts, |
104 | $displayDates |
105 | ); |
106 | } |
107 | } |
108 | return $assignments; |
109 | } |
110 | |
111 | /** |
112 | * @deprecated |
113 | */ |
114 | public function getRuntime($deliveryId) |
115 | { |
116 | return $this->getServiceLocator()->get(RuntimeService::SERVICE_ID)->getRuntime($deliveryId); |
117 | } |
118 | |
119 | |
120 | /** |
121 | * |
122 | * @param string $deliveryId |
123 | * @return array identifiers of the users |
124 | */ |
125 | public function getAssignedUsers($deliveryId) |
126 | { |
127 | $groupClass = GroupsService::singleton()->getRootClass(); |
128 | $groups = $groupClass->searchInstances([ |
129 | self::PROPERTY_GROUP_DELIVERY => $deliveryId |
130 | ], ['recursive' => true, 'like' => false]); |
131 | |
132 | $users = []; |
133 | foreach ($groups as $group) { |
134 | foreach (GroupsService::singleton()->getUsers($group) as $user) { |
135 | $users[] = $user->getUri(); |
136 | } |
137 | } |
138 | return array_unique($users); |
139 | } |
140 | |
141 | /** |
142 | * Helpers |
143 | */ |
144 | /** |
145 | * @param core_kernel_classes_Resource $delivery |
146 | */ |
147 | public function onDelete(core_kernel_classes_Resource $delivery) |
148 | { |
149 | $groupClass = GroupsService::singleton()->getRootClass(); |
150 | $assigned = $groupClass->searchInstances([ |
151 | self::PROPERTY_GROUP_DELIVERY => $delivery |
152 | ], ['like' => false, 'recursive' => true]); |
153 | |
154 | $assignationProperty = new core_kernel_classes_Property(self::PROPERTY_GROUP_DELIVERY); |
155 | foreach ($assigned as $groupInstance) { |
156 | $groupInstance->removePropertyValue($assignationProperty, $delivery); |
157 | } |
158 | } |
159 | |
160 | /** |
161 | * @param User $user |
162 | * @return array |
163 | */ |
164 | public function getDeliveryIdsByUser(User $user) |
165 | { |
166 | $deliveryUris = []; |
167 | // check if really available |
168 | foreach (GroupsService::singleton()->getGroups($user) as $group) { |
169 | $groupDeliveryUris = $group->getPropertyValues( |
170 | new \core_kernel_classes_Property(self::PROPERTY_GROUP_DELIVERY) |
171 | ); |
172 | |
173 | foreach ($groupDeliveryUris as $deliveryUri) { |
174 | $candidate = new core_kernel_classes_Resource($deliveryUri); |
175 | if (!$this->isUserExcluded($candidate, $user) && $candidate->exists()) { |
176 | $deliveryUris[$candidate->getUri()] = $candidate->getUri(); |
177 | } |
178 | } |
179 | } |
180 | |
181 | ksort($deliveryUris); |
182 | return $deliveryUris; |
183 | } |
184 | |
185 | /** |
186 | * Check if a user is excluded from a delivery |
187 | * @param core_kernel_classes_Resource $delivery |
188 | * @param User $user the URI of the user to check |
189 | * @return boolean true if excluded |
190 | */ |
191 | protected function isUserExcluded(\core_kernel_classes_Resource $delivery, User $user) |
192 | { |
193 | $excludedUsers = $delivery->getPropertyValues( |
194 | new \core_kernel_classes_Property(DeliveryContainerService::PROPERTY_EXCLUDED_SUBJECTS) |
195 | ); |
196 | |
197 | return in_array($user->getIdentifier(), $excludedUsers); |
198 | } |
199 | |
200 | /** |
201 | * Search for deliveries configured for guest access |
202 | * |
203 | * @return array |
204 | */ |
205 | public function getGuestAccessDeliveries() |
206 | { |
207 | $class = new core_kernel_classes_Class(DeliveryAssemblyService::CLASS_URI); |
208 | |
209 | return $class->searchInstances( |
210 | [ |
211 | // phpcs:disable Generic.Files.LineLength |
212 | DeliveryContainerService::PROPERTY_ACCESS_SETTINGS => DeliveryAssemblyService::PROPERTY_DELIVERY_GUEST_ACCESS |
213 | // phpcs:enable Generic.Files.LineLength |
214 | ], |
215 | ['recursive' => true] |
216 | ); |
217 | } |
218 | |
219 | /** |
220 | * Check if current user is guest |
221 | * |
222 | * @param User $user |
223 | * @return bool |
224 | */ |
225 | public function isDeliveryGuestUser(User $user) |
226 | { |
227 | return ($user instanceof GuestTestUser); |
228 | } |
229 | |
230 | /** |
231 | * @param string $deliveryIdentifier |
232 | * @param User $user |
233 | * @return bool |
234 | */ |
235 | public function isDeliveryExecutionAllowed($deliveryIdentifier, User $user) |
236 | { |
237 | $delivery = new \core_kernel_classes_Resource($deliveryIdentifier); |
238 | return $this->verifyUserAssigned($delivery, $user) |
239 | && $this->verifyTime($delivery) |
240 | && $this->verifyToken($delivery, $user); |
241 | } |
242 | |
243 | /** |
244 | * @param core_kernel_classes_Resource $delivery |
245 | * @param User $user |
246 | * @return bool |
247 | */ |
248 | protected function verifyUserAssigned(core_kernel_classes_Resource $delivery, User $user) |
249 | { |
250 | $returnValue = false; |
251 | |
252 | //check for guest access mode |
253 | if ($this->isDeliveryGuestUser($user) && $this->hasDeliveryGuestAccess($delivery)) { |
254 | $returnValue = true; |
255 | } else { |
256 | $userGroups = GroupsService::singleton()->getGroups($user); |
257 | $deliveryGroups = GroupsService::singleton()->getRootClass()->searchInstances([ |
258 | self::PROPERTY_GROUP_DELIVERY => $delivery->getUri() |
259 | ], [ |
260 | 'like' => false, 'recursive' => true |
261 | ]); |
262 | $returnValue = count(array_intersect($userGroups, $deliveryGroups)) > 0 |
263 | && !$this->isUserExcluded($delivery, $user); |
264 | } |
265 | |
266 | return $returnValue; |
267 | } |
268 | |
269 | /** |
270 | * Check if delivery configured for guest access |
271 | * |
272 | * @param core_kernel_classes_Resource $delivery |
273 | * @return bool |
274 | * @throws \common_exception_InvalidArgumentType |
275 | */ |
276 | protected function hasDeliveryGuestAccess(core_kernel_classes_Resource $delivery) |
277 | { |
278 | $returnValue = false; |
279 | |
280 | $properties = $delivery->getPropertiesValues([ |
281 | new core_kernel_classes_Property(DeliveryContainerService::PROPERTY_ACCESS_SETTINGS), |
282 | ]); |
283 | $propAccessSettings = current($properties[DeliveryContainerService::PROPERTY_ACCESS_SETTINGS ]); |
284 | $accessSetting = (!(is_object($propAccessSettings)) or ($propAccessSettings == "")) |
285 | ? null |
286 | : $propAccessSettings->getUri(); |
287 | |
288 | if (!is_null($accessSetting)) { |
289 | $returnValue = ($accessSetting === DeliveryAssemblyService::PROPERTY_DELIVERY_GUEST_ACCESS); |
290 | } |
291 | |
292 | return $returnValue; |
293 | } |
294 | |
295 | /** |
296 | * @param core_kernel_classes_Resource $delivery |
297 | * @param User $user |
298 | * @return bool |
299 | */ |
300 | protected function verifyToken(core_kernel_classes_Resource $delivery, User $user) |
301 | { |
302 | $propMaxExec = $delivery->getOnePropertyValue( |
303 | new \core_kernel_classes_Property(DeliveryContainerService::PROPERTY_MAX_EXEC) |
304 | ); |
305 | $maxExec = is_null($propMaxExec) ? 0 : $propMaxExec->literal; |
306 | |
307 | //check Tokens |
308 | $usedTokens = count($this->getServiceLocator()->get(AttemptServiceInterface::SERVICE_ID) |
309 | ->getAttempts($delivery->getUri(), $user)); |
310 | |
311 | if (($maxExec != 0) && ($usedTokens >= $maxExec)) { |
312 | \common_Logger::d("Attempt to start the compiled delivery " . $delivery->getUri() . "without tokens"); |
313 | return false; |
314 | } |
315 | return true; |
316 | } |
317 | |
318 | /** |
319 | * @param core_kernel_classes_Resource $delivery |
320 | * @return bool |
321 | */ |
322 | protected function verifyTime(core_kernel_classes_Resource $delivery) |
323 | { |
324 | $deliveryProps = $delivery->getPropertiesValues([ |
325 | DeliveryContainerService::PROPERTY_START, |
326 | DeliveryContainerService::PROPERTY_END, |
327 | ]); |
328 | |
329 | $startExec = empty($deliveryProps[DeliveryContainerService::PROPERTY_START]) |
330 | ? null |
331 | : (string)current($deliveryProps[DeliveryContainerService::PROPERTY_START]); |
332 | $stopExec = empty($deliveryProps[DeliveryContainerService::PROPERTY_END]) |
333 | ? null |
334 | : (string)current($deliveryProps[DeliveryContainerService::PROPERTY_END]); |
335 | |
336 | $startDate = date_create('@' . $startExec); |
337 | $endDate = date_create('@' . $stopExec); |
338 | if (!$this->areWeInRange($startDate, $endDate)) { |
339 | \common_Logger::d("Attempt to start the compiled delivery " . $delivery->getUri() . " at the wrong date"); |
340 | return false; |
341 | } |
342 | return true; |
343 | } |
344 | |
345 | /** |
346 | * Check if the date are in range |
347 | * @param type $startDate |
348 | * @param type $endDate |
349 | * @return boolean true if in range |
350 | */ |
351 | protected function areWeInRange($startDate, $endDate) |
352 | { |
353 | return (empty($startDate) || date_create() >= $startDate) |
354 | && (empty($endDate) || date_create() <= $endDate); |
355 | } |
356 | |
357 | /** |
358 | * Order Assignments of a given user. |
359 | * |
360 | * By default, this method relies on the taoDelivery:DisplayOrder property |
361 | * to order the assignments (Ascending order). However, implementers extending |
362 | * the GroupAssignment class are encouraged to override this method if they need |
363 | * another behaviour. |
364 | * |
365 | * @param array $assignments An array of assignments. |
366 | * @return array The $assignments array ordered. |
367 | */ |
368 | protected function orderAssignments(array $assignments) |
369 | { |
370 | usort($assignments, function ($a, $b) { |
371 | return $a->getDisplayOrder() - $b->getDisplayOrder(); |
372 | }); |
373 | |
374 | return $assignments; |
375 | } |
376 | |
377 | /** |
378 | * @param core_kernel_classes_Resource $delivery |
379 | * @param User $user |
380 | * @param $startable |
381 | * @param bool $displayAttempts |
382 | * @return AssignmentFactory |
383 | */ |
384 | protected function getAssignmentFactory( |
385 | \core_kernel_classes_Resource $delivery, |
386 | User $user, |
387 | $startable, |
388 | $displayAttempts = true, |
389 | $displayDates = true |
390 | ) { |
391 | $factory = new AssignmentFactory($delivery, $user, $startable, $displayAttempts, $displayDates); |
392 | $factory->setServiceLocator($this->getServiceLocator()); |
393 | return $factory; |
394 | } |
395 | } |