361 lines
12 KiB
PHP
361 lines
12 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* This program is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public License
|
||
|
* as published by the Free Software Foundation; under version 2
|
||
|
* of the License (non-upgradable).
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
|
*
|
||
|
* Copyright (c) 2015 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
namespace oat\taoDeliveryRdf\model;
|
||
|
|
||
|
use oat\taoGroups\models\GroupsService;
|
||
|
use oat\oatbox\user\User;
|
||
|
use oat\oatbox\service\ConfigurableService;
|
||
|
use core_kernel_classes_Resource;
|
||
|
use core_kernel_classes_Class;
|
||
|
use \core_kernel_classes_Property;
|
||
|
use oat\taoDelivery\model\AssignmentService;
|
||
|
use oat\taoDeliveryRdf\model\guest\GuestTestUser;
|
||
|
use oat\taoDelivery\model\RuntimeService;
|
||
|
use oat\taoDelivery\model\AttemptServiceInterface;
|
||
|
|
||
|
/**
|
||
|
* Service to manage the assignment of users to deliveries
|
||
|
*
|
||
|
* @access public
|
||
|
* @author Joel Bout, <joel@taotesting.com>
|
||
|
* @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;
|
||
|
}
|
||
|
}
|