Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
41 / 41
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
LtiAssignment
100.00% covered (success)
100.00%
41 / 41
100.00% covered (success)
100.00%
3 / 3
13
100.00% covered (success)
100.00%
1 / 1
 isDeliveryExecutionAllowed
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 verifyToken
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
7
 verifyAvailabilityFrame
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
5
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) 2016 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT);
19 *
20 *
21 */
22
23namespace oat\ltiDeliveryProvider\model;
24
25use common_exception_Error;
26use core_kernel_classes_Resource as KernelResource;
27use core_kernel_persistence_Exception;
28use oat\generis\model\OntologyAwareTrait;
29use oat\oatbox\log\LoggerAwareTrait;
30use oat\oatbox\service\ConfigurableService;
31use oat\oatbox\session\SessionService;
32use oat\taoDelivery\model\AttemptServiceInterface;
33use oat\taoDeliveryRdf\model\DeliveryAssemblyService;
34use oat\taoDeliveryRdf\model\DeliveryContainerService;
35use oat\oatbox\user\User;
36use oat\taoLti\models\classes\LtiClientException;
37use oat\taoLti\models\classes\LtiException;
38use oat\taoLti\models\classes\LtiMessages\LtiErrorMessage;
39use oat\taoLti\models\classes\LtiVariableMissingException;
40use oat\taoLti\models\classes\TaoLtiSession;
41
42/**
43 * Class LtiAssignment
44 * @package oat\ltiDeliveryProvider\model
45 * @author Aleh Hutnikau, <hutnikau@1pt.com>
46 */
47class LtiAssignment extends ConfigurableService
48{
49    use OntologyAwareTrait;
50    use LoggerAwareTrait;
51
52    public const LTI_MAX_ATTEMPTS_VARIABLE = 'custom_max_attempts';
53
54    /**
55     * @deprecated Use LtiAssignmentAuthorizationService::SERVICE_ID instead
56     */
57    public const LTI_SERVICE_ID = 'ltiDeliveryProvider/assignment';
58
59    public const SERVICE_ID = 'ltiDeliveryProvider/assignment';
60
61    /**
62     * @param string $deliveryIdentifier
63     * @param User $user
64     * @return bool
65     */
66    public function isDeliveryExecutionAllowed($deliveryIdentifier, User $user)
67    {
68        $delivery = $this->getResource($deliveryIdentifier);
69
70        $this->verifyAvailabilityFrame($delivery);
71        return $this->verifyToken($delivery, $user);
72    }
73
74    /**
75     * Check Max. number of executions
76     *
77     * @param KernelResource $delivery
78     * @param User $user
79     * @return bool
80     * @throws LtiException
81     * @throws common_exception_Error
82     * @throws core_kernel_persistence_Exception
83     * @throws LtiVariableMissingException
84     */
85    protected function verifyToken(KernelResource $delivery, User $user)
86    {
87        $propMaxExec = $delivery->getOnePropertyValue($this->getProperty(DeliveryContainerService::PROPERTY_MAX_EXEC));
88        $maxExec = is_null($propMaxExec) ? 0 : (int) $propMaxExec->literal;
89
90        $currentSession = $this->getServiceLocator()->get(SessionService::SERVICE_ID)->getCurrentSession();
91
92        if ($currentSession instanceof TaoLtiSession) {
93            $launchData = $currentSession->getLaunchData();
94            if ($launchData->hasVariable(self::LTI_MAX_ATTEMPTS_VARIABLE)) {
95                $val = $launchData->getVariable(self::LTI_MAX_ATTEMPTS_VARIABLE);
96                if (!is_numeric($val)) {
97                    throw new LtiClientException(
98                        __('"max_attempts" variable must me numeric.'),
99                        LtiErrorMessage::ERROR_INVALID_PARAMETER
100                    );
101                }
102                $maxExec = (int) $val;
103            }
104        }
105
106        //check Tokens
107        $usedTokens = count($this->getServiceLocator()->get(AttemptServiceInterface::SERVICE_ID)
108            ->getAttempts($delivery->getUri(), $user));
109
110        if (($maxExec != 0) && ($usedTokens >= $maxExec)) {
111            $this->logDebug("Attempt to start the compiled delivery " . $delivery->getUri() . " without tokens");
112            throw new LtiClientException(
113                __('Attempts limit has been reached.'),
114                LtiErrorMessage::ERROR_LAUNCH_FORBIDDEN
115            );
116        }
117        return true;
118    }
119
120    private function verifyAvailabilityFrame(KernelResource $delivery): void
121    {
122        $this->logInfo("Verify availability frame for delivery {$delivery->getUri()}");
123        $scheduledStartTimeProperty = $delivery->getOnePropertyValue(
124            $this->getProperty(DeliveryAssemblyService::PROPERTY_START)
125        );
126        $scheduledEndTimeProperty = $delivery->getOnePropertyValue(
127            $this->getProperty(DeliveryAssemblyService::PROPERTY_END)
128        );
129        $scheduledStartTime = (int)(string)$scheduledStartTimeProperty ?: 0;
130        $scheduledEndTime = (int)(string)$scheduledEndTimeProperty ?: PHP_INT_MAX;
131
132        $currentTime = time();
133
134        if ($scheduledStartTime > $currentTime || $scheduledEndTime <= $currentTime) {
135            $this->logDebug("Attempt to start the compiled delivery {$delivery->getUri()} at unscheduled time");
136
137            throw new LtiClientException(
138                __('The delivery is currently unavailable.'),
139                LtiErrorMessage::ERROR_LAUNCH_FORBIDDEN
140            );
141        }
142    }
143}