Passed
Push — master ( 3be753...7af7b8 )
by Julito
10:23
created

SessionVoter::voteOnAttribute()   D

Complexity

Conditions 18
Paths 20

Size

Total Lines 84
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 18
eloc 40
nc 20
nop 3
dl 0
loc 84
rs 4.8666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
namespace Chamilo\CoreBundle\Security\Authorization\Voter;
5
6
use Chamilo\CoreBundle\Entity\Manager\CourseManager;
7
use Chamilo\CoreBundle\Entity\Session;
8
use Chamilo\UserBundle\Entity\User;
9
use Doctrine\ORM\EntityManager;
10
use Doctrine\ORM\EntityManagerInterface;
11
use Symfony\Component\DependencyInjection\ContainerInterface;
12
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
13
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
14
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
17
/**
18
 * Class SessionVoter.
19
 *
20
 * @package Chamilo\CoreBundle\Security\Authorization\Voter
21
 */
22
class SessionVoter extends Voter
23
{
24
    public const VIEW = 'VIEW';
25
    public const EDIT = 'EDIT';
26
    public const DELETE = 'DELETE';
27
28
    private $entityManager;
29
    private $courseManager;
30
    private $authorizationChecker;
31
    private $container;
32
33
    /**
34
     * @param EntityManagerInterface        $entityManager
35
     * @param CourseManager                 $courseManager
36
     * @param AuthorizationCheckerInterface $authorizationChecker
37
     * @param ContainerInterface            $container
38
     */
39
    public function __construct(
40
        EntityManagerInterface $entityManager,
41
        CourseManager $courseManager,
42
        AuthorizationCheckerInterface $authorizationChecker,
43
        ContainerInterface $container
44
    ) {
45
        $this->entityManager = $entityManager;
46
        $this->courseManager = $courseManager;
47
        $this->authorizationChecker = $authorizationChecker;
48
        $this->container = $container;
49
    }
50
51
    /**
52
     * @return AuthorizationCheckerInterface
53
     */
54
    public function getAuthorizationChecker()
55
    {
56
        return $this->authorizationChecker;
57
    }
58
59
    /**
60
     * @return EntityManager
61
     */
62
    public function getEntityManager()
63
    {
64
        return $this->entityManager;
65
    }
66
67
    /**
68
     * @return CourseManager
69
     */
70
    public function getCourseManager()
71
    {
72
        return $this->courseManager;
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function supports($attribute, $subject): bool
79
    {
80
        $options = [
81
            self::VIEW,
82
            self::EDIT,
83
            self::DELETE,
84
        ];
85
86
        return $subject instanceof Session && in_array($attribute, $options);
87
    }
88
89
    /**
90
     * Check if user has access to a session.
91
     *
92
     * {@inheritdoc}
93
     */
94
    protected function voteOnAttribute($attribute, $session, TokenInterface $token): bool
95
    {
96
        /** @var User $user */
97
        $user = $token->getUser();
98
99
        // Make sure there is a user object (i.e. that the user is logged in)
100
        if (!$user instanceof UserInterface) {
101
            return false;
102
        }
103
104
        $authChecker = $this->getAuthorizationChecker();
105
106
        // Admins have access to everything
107
        if ($authChecker->isGranted('ROLE_ADMIN')) {
108
            return true;
109
        }
110
111
        // Checks if the current course was set up
112
        // $session->getCurrentCourse() is set in the class CourseListener
113
        /** @var Session $session */
114
        $currentCourse = $session->getCurrentCourse();
115
116
        switch ($attribute) {
117
            case self::VIEW:
118
                $userIsGeneralCoach = $session->isUserGeneralCoach($user);
119
                $userIsCourseCoach = $session->hasCoachInCourseWithStatus($user, $currentCourse);
120
                $userIsStudent = $session->hasUserInCourse($user, $currentCourse, Session::STUDENT);
121
122
                if (empty($session->getDuration())) {
123
                    // General coach
124
                    if ($userIsGeneralCoach && $session->isActiveForCoach()) {
125
                        $user->addRole('ROLE_CURRENT_SESSION_COURSE_TEACHER');
126
127
                        return true;
128
                    }
129
                    // Course-Coach access
130
                    if ($userIsCourseCoach && $session->isActiveForCoach()) {
131
                        $user->addRole('ROLE_CURRENT_SESSION_COURSE_TEACHER');
132
133
                        return true;
134
                    }
135
136
                    // Student access
137
                    if ($userIsStudent && $session->isActiveForStudent()) {
138
                        $user->addRole('ROLE_CURRENT_SESSION_COURSE_STUDENT');
139
140
                        return true;
141
                    }
142
143
                    return false;
144
                }
145
146
                if ($this->sessionIsAvailableByDuration($session, $user)) {
147
                    if ($userIsGeneralCoach) {
148
                        $user->addRole('ROLE_CURRENT_SESSION_COURSE_TEACHER');
149
                    }
150
151
                    if ($userIsCourseCoach) {
152
                        $user->addRole('ROLE_CURRENT_SESSION_COURSE_TEACHER');
153
                    }
154
155
                    if ($userIsStudent) {
156
                        $user->addRole('ROLE_CURRENT_SESSION_COURSE_STUDENT');
157
                    }
158
159
                    return true;
160
                }
161
162
                return false;
163
            case self::EDIT:
164
            case self::DELETE:
165
                $canEdit = $this->canEditSession($user, $session, false);
166
167
                if ($canEdit) {
168
                    $user->addRole('ROLE_CURRENT_SESSION_COURSE_TEACHER');
169
170
                    return true;
171
                }
172
173
                return false;
174
        }
175
176
        // User don't have access to the session
177
        return false;
178
    }
179
180
    /**
181
     * @param Session $session
182
     * @param User    $user
183
     *
184
     * @return bool
185
     */
186
    private function sessionIsAvailableByDuration(Session $session, User $user)
187
    {
188
        $duration = $session->getDuration() * 24 * 60 * 60;
189
        $courseAccess = \CourseManager::getFirstCourseAccessPerSessionAndUser(
190
            $session->getId(),
191
            $user->getId()
192
        );
193
194
        // If there is a session duration but there is no previous
195
        // access by the user, then the session is still available
196
        if (count($courseAccess) == 0) {
197
            return true;
198
        }
199
200
        $currentTime = time();
201
        $firstAccess = 0;
202
203
        if (isset($courseAccess['login_course_date'])) {
204
            $firstAccess = api_strtotime(
205
                $courseAccess['login_course_date'],
206
                'UTC'
207
            );
208
        }
209
210
        $userDurationData = \SessionManager::getUserSession(
211
            $user->getId(),
212
            $session->getId()
213
        );
214
        $userDuration = 0;
215
216
        if (isset($userDurationData['duration'])) {
217
            $userDuration = (int) $userDurationData['duration'] * 24 * 60 * 60;
218
        }
219
220
        $totalDuration = $firstAccess + $duration + $userDuration;
221
222
        return $totalDuration > $currentTime;
223
    }
224
225
    /**
226
     * @param User    $user
227
     * @param Session $session
228
     * @param bool    $checkSession
229
     *
230
     * @return bool
231
     */
232
    private function canEditSession(User $user, Session $session, $checkSession = true): bool
233
    {
234
        if (!$this->allowToManageSessions()) {
235
            return false;
236
        }
237
238
        $authChecker = $this->getAuthorizationChecker();
239
240
        if ($authChecker->isGranted('ROLE_ADMIN') && $this->allowed($user, $session)) {
241
            return true;
242
        }
243
244
        if ($checkSession) {
245
            if ($this->allowed($user, $session)) {
246
                return true;
247
            }
248
249
            return false;
250
        }
251
252
        return true;
253
    }
254
255
    /**
256
     * @return bool
257
     */
258
    private function allowToManageSessions(): bool
259
    {
260
        if ($this->allowManageAllSessions()) {
261
            return true;
262
        }
263
264
        $authChecker = $this->getAuthorizationChecker();
265
        $settingsManager = $this->container->get('chamilo.settings.manager');
266
        $setting = $settingsManager->getSetting('session.allow_teachers_to_create_sessions');
267
268
        if ($authChecker->isGranted('ROLE_TEACHER') && $setting === 'true') {
269
            return true;
270
        }
271
272
        return false;
273
    }
274
275
    /**
276
     * @return bool
277
     */
278
    private function allowManageAllSessions(): bool
279
    {
280
        $authChecker = $this->getAuthorizationChecker();
281
282
        if ($authChecker->isGranted('ROLE_ADMIN') || $authChecker->isGranted('ROLE_SESSION_MANAGER')) {
283
            return true;
284
        }
285
286
        return false;
287
    }
288
289
    /**
290
     * @param User    $user
291
     * @param Session $session
292
     *
293
     * @return bool
294
     */
295
    private function allowed(User $user, Session $session)
296
    {
297
        $authChecker = $this->getAuthorizationChecker();
298
299
        if ($authChecker->isGranted('ROLE_ADMIN')) {
300
            return true;
301
        }
302
303
        $settingsManager = $this->container->get('chamilo.settings.manager');
304
305
        if ($authChecker->isGranted('ROLE_SESSION_MANAGER') &&
306
            $settingsManager->getSetting('session.allow_session_admins_to_manage_all_sessions') !== 'true'
307
        ) {
308
            if ($session->getSessionAdminId() !== $user->getId()) {
309
                return false;
310
            }
311
        }
312
313
        if ($authChecker->isGranted('ROLE_ADMIN') &&
314
            $settingsManager->getSetting('session.allow_teachers_to_create_sessions') === 'true'
315
        ) {
316
            if ($session->getGeneralCoach()->getId() !== $user->getId()) {
317
                return false;
318
            }
319
        }
320
321
        return true;
322
    }
323
}
324