* @package taoDelivery */ class GroupAssignment extends ConfigurableService implements AssignmentService { /** * Interface part */ const PROPERTY_GROUP_DELIVERY = 'http://www.tao.lu/Ontologies/TAOGroup.rdf#Deliveries'; const DISPLAY_ATTEMPTS_OPTION = 'display_attempts'; const DISPLAY_DATES_OPTION = 'display_dates'; /** * (non-PHPdoc) * @see \oat\taoDelivery\model\AssignmentService::getAssignments() */ public function getAssignments(User $user) { $assignments = []; foreach ($this->getAssignmentFactories($user) as $factory) { $assignments[] = $factory->toAssignment(); } return $this->orderAssignments($assignments); } /** * @param User $user * @return array */ public function getAssignmentFactories(User $user) { $assignments = []; $displayAttempts = ($this->hasOption(self::DISPLAY_ATTEMPTS_OPTION)) ? $this->getOption(self::DISPLAY_ATTEMPTS_OPTION) : true; $displayDates = ($this->hasOption(self::DISPLAY_DATES_OPTION)) ? $this->getOption(self::DISPLAY_DATES_OPTION) : true; if ($this->isDeliveryGuestUser($user)) { foreach ($this->getGuestAccessDeliveries() as $id) { $delivery = new \core_kernel_classes_Resource($id); $startable = $this->verifyTime($delivery) && $this->verifyToken($delivery, $user); $assignments[] = $this->getAssignmentFactory($delivery, $user, $startable, $displayAttempts, $displayDates); } } else { foreach ($this->getDeliveryIdsByUser($user) as $id) { $delivery = new \core_kernel_classes_Resource($id); $startable = $this->verifyTime($delivery) && $this->verifyToken($delivery, $user); $assignments[] = $this->getAssignmentFactory($delivery, $user, $startable, $displayAttempts, $displayDates); } } return $assignments; } /** * @deprecated */ public function getRuntime($deliveryId) { return $this->getServiceLocator()->get(RuntimeService::SERVICE_ID)->getRuntime($deliveryId); } /** * * @param string $deliveryId * @return array identifiers of the users */ public function getAssignedUsers($deliveryId) { $groupClass = GroupsService::singleton()->getRootClass(); $groups = $groupClass->searchInstances([ self::PROPERTY_GROUP_DELIVERY => $deliveryId ], ['recursive' => true, 'like' => false]); $users = []; foreach ($groups as $group) { foreach (GroupsService::singleton()->getUsers($group) as $user) { $users[] = $user->getUri(); } } return array_unique($users); } /** * Helpers */ /** * @param core_kernel_classes_Resource $delivery */ public function onDelete(core_kernel_classes_Resource $delivery) { $groupClass = GroupsService::singleton()->getRootClass(); $assigned = $groupClass->searchInstances([ self::PROPERTY_GROUP_DELIVERY => $delivery ], ['like' => false, 'recursive' => true]); $assignationProperty = new core_kernel_classes_Property(self::PROPERTY_GROUP_DELIVERY); foreach ($assigned as $groupInstance) { $groupInstance->removePropertyValue($assignationProperty, $delivery); } } /** * @param User $user * @return array */ public function getDeliveryIdsByUser(User $user) { $deliveryUris = []; // check if really available foreach (GroupsService::singleton()->getGroups($user) as $group) { foreach ($group->getPropertyValues(new \core_kernel_classes_Property(self::PROPERTY_GROUP_DELIVERY)) as $deliveryUri) { $candidate = new core_kernel_classes_Resource($deliveryUri); if (!$this->isUserExcluded($candidate, $user) && $candidate->exists()) { $deliveryUris[$candidate->getUri()] = $candidate->getUri(); } } } ksort($deliveryUris); return $deliveryUris; } /** * Check if a user is excluded from a delivery * @param core_kernel_classes_Resource $delivery * @param User $user the URI of the user to check * @return boolean true if excluded */ protected function isUserExcluded(\core_kernel_classes_Resource $delivery, User $user) { $excludedUsers = $delivery->getPropertyValues(new \core_kernel_classes_Property(DeliveryContainerService::PROPERTY_EXCLUDED_SUBJECTS)); return in_array($user->getIdentifier(), $excludedUsers); } /** * Search for deliveries configured for guest access * * @return array */ public function getGuestAccessDeliveries() { $class = new core_kernel_classes_Class(DeliveryAssemblyService::CLASS_URI); return $class->searchInstances( [ DeliveryContainerService::PROPERTY_ACCESS_SETTINGS => DeliveryAssemblyService::PROPERTY_DELIVERY_GUEST_ACCESS ], ['recursive' => true] ); } /** * Check if current user is guest * * @param User $user * @return bool */ public function isDeliveryGuestUser(User $user) { return ($user instanceof GuestTestUser); } /** * @param string $deliveryIdentifier * @param User $user * @return bool */ public function isDeliveryExecutionAllowed($deliveryIdentifier, User $user) { $delivery = new \core_kernel_classes_Resource($deliveryIdentifier); return $this->verifyUserAssigned($delivery, $user) && $this->verifyTime($delivery) && $this->verifyToken($delivery, $user); } /** * @param core_kernel_classes_Resource $delivery * @param User $user * @return bool */ protected function verifyUserAssigned(core_kernel_classes_Resource $delivery, User $user) { $returnValue = false; //check for guest access mode if ($this->isDeliveryGuestUser($user) && $this->hasDeliveryGuestAccess($delivery)) { $returnValue = true; } else { $userGroups = GroupsService::singleton()->getGroups($user); $deliveryGroups = GroupsService::singleton()->getRootClass()->searchInstances([ self::PROPERTY_GROUP_DELIVERY => $delivery->getUri() ], [ 'like' => false, 'recursive' => true ]); $returnValue = count(array_intersect($userGroups, $deliveryGroups)) > 0 && !$this->isUserExcluded($delivery, $user); } return $returnValue; } /** * Check if delivery configured for guest access * * @param core_kernel_classes_Resource $delivery * @return bool * @throws \common_exception_InvalidArgumentType */ protected function hasDeliveryGuestAccess(core_kernel_classes_Resource $delivery) { $returnValue = false; $properties = $delivery->getPropertiesValues([ new core_kernel_classes_Property(DeliveryContainerService::PROPERTY_ACCESS_SETTINGS), ]); $propAccessSettings = current($properties[DeliveryContainerService::PROPERTY_ACCESS_SETTINGS ]); $accessSetting = (!(is_object($propAccessSettings)) or ($propAccessSettings == "")) ? null : $propAccessSettings->getUri(); if (!is_null($accessSetting)) { $returnValue = ($accessSetting === DeliveryAssemblyService::PROPERTY_DELIVERY_GUEST_ACCESS); } return $returnValue; } /** * @param core_kernel_classes_Resource $delivery * @param User $user * @return bool */ protected function verifyToken(core_kernel_classes_Resource $delivery, User $user) { $propMaxExec = $delivery->getOnePropertyValue(new \core_kernel_classes_Property(DeliveryContainerService::PROPERTY_MAX_EXEC)); $maxExec = is_null($propMaxExec) ? 0 : $propMaxExec->literal; //check Tokens $usedTokens = count($this->getServiceLocator()->get(AttemptServiceInterface::SERVICE_ID) ->getAttempts($delivery->getUri(), $user)); if (($maxExec != 0) && ($usedTokens >= $maxExec)) { \common_Logger::d("Attempt to start the compiled delivery " . $delivery->getUri() . "without tokens"); return false; } return true; } /** * @param core_kernel_classes_Resource $delivery * @return bool */ protected function verifyTime(core_kernel_classes_Resource $delivery) { $deliveryProps = $delivery->getPropertiesValues([ DeliveryContainerService::PROPERTY_START, DeliveryContainerService::PROPERTY_END, ]); $startExec = empty($deliveryProps[DeliveryContainerService::PROPERTY_START]) ? null : (string)current($deliveryProps[DeliveryContainerService::PROPERTY_START]); $stopExec = empty($deliveryProps[DeliveryContainerService::PROPERTY_END]) ? null : (string)current($deliveryProps[DeliveryContainerService::PROPERTY_END]); $startDate = date_create('@' . $startExec); $endDate = date_create('@' . $stopExec); if (!$this->areWeInRange($startDate, $endDate)) { \common_Logger::d("Attempt to start the compiled delivery " . $delivery->getUri() . " at the wrong date"); return false; } return true; } /** * Check if the date are in range * @param type $startDate * @param type $endDate * @return boolean true if in range */ protected function areWeInRange($startDate, $endDate) { return (empty($startDate) || date_create() >= $startDate) && (empty($endDate) || date_create() <= $endDate); } /** * Order Assignments of a given user. * * By default, this method relies on the taoDelivery:DisplayOrder property * to order the assignments (Ascending order). However, implementers extending * the GroupAssignment class are encouraged to override this method if they need * another behaviour. * * @param array $assignments An array of assignments. * @return array The $assignments array ordered. */ protected function orderAssignments(array $assignments) { usort($assignments, function ($a, $b) { return $a->getDisplayOrder() - $b->getDisplayOrder(); }); return $assignments; } /** * @param core_kernel_classes_Resource $delivery * @param User $user * @param $startable * @param bool $displayAttempts * @return AssignmentFactory */ protected function getAssignmentFactory(\core_kernel_classes_Resource $delivery, User $user, $startable, $displayAttempts = true, $displayDates = true) { $factory = new AssignmentFactory($delivery, $user, $startable, $displayAttempts, $displayDates); $factory->setServiceLocator($this->getServiceLocator()); return $factory; } }