Passed
Push — master ( bd8ed8...9d8dba )
by Angel Fernando Quiroz
09:46 queued 18s
created

SessionVoter::allowed()   B

Complexity

Conditions 8
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 11
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 21
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Security\Authorization\Voter;
8
9
use Chamilo\CoreBundle\Entity\Session;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\Settings\SettingsManager;
12
use Symfony\Bundle\SecurityBundle\Security;
13
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
14
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
15
use Symfony\Component\Security\Core\User\UserInterface;
16
17
/**
18
 * @todo remove legacy code.
19
 *
20
 * @extends Voter<'VIEW'|'EDIT'|'DELETE', Session>
21
 */
22
class SessionVoter extends Voter
23
{
24
    public const VIEW = 'VIEW';
25
    public const EDIT = 'EDIT';
26
    public const DELETE = 'DELETE';
27
28
    public function __construct(
29
        private readonly Security $security,
30
        private readonly SettingsManager $settingsManager
31
    ) {}
32
33
    protected function supports(string $attribute, $subject): bool
34
    {
35
        $options = [
36
            self::VIEW,
37
            self::EDIT,
38
            self::DELETE,
39
        ];
40
41
        return $subject instanceof Session && \in_array($attribute, $options, true);
42
    }
43
44
    /**
45
     * Check if user has access to a session.
46
     *
47
     * {@inheritdoc}
48
     */
49
    protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
50
    {
51
        /** @var User $user */
52
        $user = $token->getUser();
53
54
        // Make sure there is a user object (i.e. that the user is logged in)
55
        if (!$user instanceof UserInterface) {
56
            return false;
57
        }
58
59
        // Admins have access to everything.
60
        if ($this->security->isGranted('ROLE_ADMIN')) {
61
            return true;
62
        }
63
64
        // Checks if the current course was set up
65
        // $session->getCurrentCourse() is set in the class CidReqListener.
66
        /** @var Session $session */
67
        $session = $subject;
68
        $currentCourse = $session->getCurrentCourse();
69
70
        // Course checks.
71
        if ($currentCourse && $currentCourse->isHidden()) {
72
            return false;
73
        }
74
75
        switch ($attribute) {
76
            case self::VIEW:
77
                // @todo improve performance.
78
                $userIsGeneralCoach = $session->hasUserAsGeneralCoach($user);
79
                if (null === $currentCourse) {
80
                    $userIsStudent = $session->getSessionRelCourseByUser($user, Session::STUDENT)->count() > 0;
81
                    $userIsCourseCoach = $session->hasCoachInCourseList($user); // The current course will be checked in CourseVoter.
82
                } else {
83
                    $userIsCourseCoach = $session->hasCourseCoachInCourse($user, $currentCourse);
84
                    $userIsStudent = $session->hasUserInCourse($user, $currentCourse, Session::STUDENT);
85
                }
86
                $duration = (int) $session->getDuration();
87
                if (0 === $duration) {
88
                    // General coach.
89
                    if ($userIsGeneralCoach && $session->isActiveForCoach()) {
90
                        $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_TEACHER);
91
92
                        return true;
93
                    }
94
95
                    // Course-Coach access.
96
                    if ($userIsCourseCoach && $session->isActiveForCoach()) {
97
                        $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_TEACHER);
98
99
                        return true;
100
                    }
101
102
                    // Student access.
103
                    if ($userIsStudent && $session->isActiveForStudent()) {
104
                        $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_STUDENT);
105
106
                        return true;
107
                    }
108
                }
109
110
                if ($session->isAvailableByDurationForUser($user)) {
111
                    if ($userIsGeneralCoach) {
112
                        $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_TEACHER);
113
114
                        return true;
115
                    }
116
117
                    if ($userIsCourseCoach) {
118
                        $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_TEACHER);
119
120
                        return true;
121
                    }
122
123
                    if ($userIsStudent) {
124
                        $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_STUDENT);
125
126
                        return true;
127
                    }
128
                }
129
130
                return false;
131
132
            case self::EDIT:
133
            case self::DELETE:
134
                $canEdit = $this->canEditSession($user, $session, false);
135
136
                if ($canEdit) {
137
                    $user->addRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_SESSION_TEACHER);
138
139
                    return true;
140
                }
141
142
                return false;
143
        }
144
145
        // User don't have access to the session
146
        return false;
147
    }
148
149
    private function canEditSession(User $user, Session $session, bool $checkSession = true): bool
150
    {
151
        if (!$this->allowToManageSessions()) {
152
            return false;
153
        }
154
155
        if ($this->security->isGranted('ROLE_ADMIN') && $this->allowed($user, $session)) {
156
            return true;
157
        }
158
159
        if ($checkSession) {
160
            return $this->allowed($user, $session);
161
        }
162
163
        return true;
164
    }
165
166
    private function allowToManageSessions(): bool
167
    {
168
        if ($this->allowManageAllSessions()) {
169
            return true;
170
        }
171
172
        $setting = $this->settingsManager->getSetting('session.allow_teachers_to_create_sessions');
173
174
        return 'true' === $setting && $this->security->isGranted('ROLE_TEACHER');
175
    }
176
177
    private function allowManageAllSessions(): bool
178
    {
179
        return $this->security->isGranted('ROLE_ADMIN') || $this->security->isGranted('ROLE_SESSION_MANAGER');
180
    }
181
182
    private function allowed(User $user, Session $session): bool
183
    {
184
        if ($this->security->isGranted('ROLE_ADMIN')) {
185
            return true;
186
        }
187
188
        if ($this->security->isGranted('ROLE_SESSION_MANAGER')
189
            && 'true' !== $this->settingsManager->getSetting('session.allow_session_admins_to_manage_all_sessions')
190
            && !$session->hasUserAsSessionAdmin($user)
191
        ) {
192
            return false;
193
        }
194
195
        if ($this->security->isGranted('ROLE_TEACHER')
196
            && 'true' === $this->settingsManager->getSetting('session.allow_teachers_to_create_sessions')
197
            && !$session->hasUserAsGeneralCoach($user)
198
        ) {
199
            return false;
200
        }
201
202
        return true;
203
    }
204
}
205