Passed
Push — master ( e6c349...49aad9 )
by Julito
10:08
created

ResourceNodeVoter::voteOnAttribute()   F

Complexity

Conditions 26
Paths 133

Size

Total Lines 192
Code Lines 96

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 26
eloc 96
nc 133
nop 3
dl 0
loc 192
rs 3.8916
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\Course;
7
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
8
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
9
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
10
use Chamilo\CoreBundle\Entity\Session;
11
use Symfony\Component\DependencyInjection\ContainerInterface;
12
use Symfony\Component\Security\Acl\Permission\MaskBuilder;
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
use Zend\Permissions\Acl\Acl;
17
//use Zend\Permissions\Acl\Resource\GenericResource as Resource;
18
use Zend\Permissions\Acl\Resource\GenericResource as SecurityResource;
19
use Zend\Permissions\Acl\Role\GenericRole as Role;
20
21
//use Sonata\AdminBundle\Security\Acl\Permission\MaskBuilder;
22
23
/**
24
 * Class ResourceNodeVoter.
25
 *
26
 * @package Chamilo\CoreBundle\Security\Authorization\Voter
27
 */
28
class ResourceNodeVoter extends Voter
29
{
30
    public const VIEW = 'VIEW';
31
    public const CREATE = 'CREATE';
32
    public const EDIT = 'EDIT';
33
    public const DELETE = 'DELETE';
34
    public const EXPORT = 'EXPORT';
35
36
    public const ROLE_CURRENT_COURSE_TEACHER = 'ROLE_CURRENT_COURSE_TEACHER';
37
    public const ROLE_CURRENT_COURSE_STUDENT = 'ROLE_CURRENT_COURSE_STUDENT';
38
    public const ROLE_CURRENT_SESSION_COURSE_TEACHER = 'ROLE_CURRENT_SESSION_COURSE_TEACHER';
39
    public const ROLE_CURRENT_SESSION_COURSE_STUDENT = 'ROLE_CURRENT_SESSION_COURSE_STUDENT';
40
41
    protected $container;
42
43
    /**
44
     * Constructor.
45
     *
46
     * @param ContainerInterface $container
47
     */
48
    public function __construct(ContainerInterface $container)
49
    {
50
        $this->container = $container;
51
    }
52
53
    /**
54
     * @return int
55
     */
56
    public static function getReaderMask(): int
57
    {
58
        $builder = new MaskBuilder();
59
        $builder
60
            ->add(self::VIEW)
61
        ;
62
63
        return $builder->get();
64
    }
65
66
    /**
67
     * @return int
68
     */
69
    public static function getEditorMask(): int
70
    {
71
        $builder = new MaskBuilder();
72
        $builder
73
            ->add(self::VIEW)
74
            ->add(self::EDIT)
75
        ;
76
77
        return $builder->get();
78
    }
79
80
    /**
81
     * {@inheritdoc}
82
     */
83
    protected function supports($attribute, $subject): bool
84
    {
85
        $options = [
86
            self::VIEW,
87
            self::CREATE,
88
            self::EDIT,
89
            self::DELETE,
90
            self::EXPORT,
91
        ];
92
93
        // if the attribute isn't one we support, return false
94
        if (!in_array($attribute, $options)) {
95
            return false;
96
        }
97
98
        // only vote on Post objects inside this voter
99
        if (!$subject instanceof ResourceNode) {
100
            return false;
101
        }
102
103
        return true;
104
    }
105
106
    /**
107
     * @param string         $attribute
108
     * @param ResourceNode   $resourceNode
109
     * @param TokenInterface $token
110
     *
111
     * @return bool
112
     */
113
    protected function voteOnAttribute($attribute, $resourceNode, TokenInterface $token): bool
114
    {
115
        $user = $token->getUser();
116
117
        // Make sure there is a user object (i.e. that the user is logged in)
118
        if (!$user instanceof UserInterface) {
119
            return false;
120
        }
121
122
        // Checking admin roles
123
        $authChecker = $this->container->get('security.authorization_checker');
124
125
        // Admins have access to everything
126
        if ($authChecker->isGranted('ROLE_ADMIN')) {
127
            return true;
128
        }
129
130
        // Check if I'm the owner
131
        $creator = $resourceNode->getCreator();
132
133
        if ($creator instanceof UserInterface &&
134
            $user->getUsername() === $creator->getUsername()) {
135
            return true;
136
        }
137
138
        // Checking possible links connected to this resource
139
        $request = $this->container->get('request_stack')->getCurrentRequest();
140
141
        $courseCode = $request->get('course');
142
        $sessionId = $request->get('session');
143
144
        $links = $resourceNode->getResourceLinks();
145
        $linkFound = false;
146
147
        $courseManager = $this->container->get('chamilo_core.entity.manager.course_manager');
148
149
        /** @var ResourceLink $link */
150
        foreach ($links as $link) {
151
            // Block access if visibility is deleted.
152
            if ($link->getVisibility() === ResourceLink::VISIBILITY_DELETED) {
153
                $linkFound = false;
154
                break;
155
            }
156
            $linkUser = $link->getUser();
157
            $linkCourse = $link->getCourse();
158
            $linkSession = $link->getSession();
159
            $linkUserGroup = $link->getUserGroup();
160
161
            // Check if resource was sent to the current user.
162
            if ($linkUser instanceof UserInterface &&
163
                $linkUser->getUsername() === $creator->getUsername()
164
            ) {
165
                $linkFound = true;
166
                break;
167
            }
168
169
            // @todo Check if resource was sent to a usergroup
170
            // @todo Check if resource was sent to a group inside a course
171
172
            // Check if resource was sent to a course inside a session
173
            if ($linkSession instanceof Session && !empty($sessionId) &&
174
                $linkCourse instanceof Course && !empty($courseCode)
175
            ) {
176
                $session = $this->container->get('chamilo_core.entity.manager.session_manager')->find($sessionId);
177
                $course = $courseManager->findOneByCode($courseCode);
178
                if ($session instanceof Session &&
179
                    $course instanceof Course &&
180
                    $linkCourse->getCode() === $course->getCode() &&
181
                    $linkSession->getId() === $session->getId()
182
                ) {
183
                    $linkFound = true;
184
                    break;
185
                }
186
            }
187
188
            // Check if resource was sent to a course
189
            if ($linkCourse instanceof Course && !empty($courseCode)) {
190
                $course = $courseManager->findOneByCode($courseCode);
191
                if ($course instanceof Course &&
192
                    $linkCourse->getCode() === $course->getCode()
193
                ) {
194
                    $linkFound = true;
195
                    break;
196
                }
197
            }
198
        }
199
200
        // No link was found or not available
201
        if (false === $linkFound) {
202
            return false;
203
        }
204
205
        // Getting rights from the link
206
        $rightFromResourceLink = $link->getResourceRight();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $link seems to be defined by a foreach iteration on line 150. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
207
208
        if ($rightFromResourceLink->count()) {
209
            // Taken rights from the link
210
            $rights = $rightFromResourceLink;
211
        } else {
212
            // Taken the rights from the default tool
213
            //$rights = $link->getResourceNode()->getTool()->getToolResourceRight();
214
            //$rights = $link->getResourceNode()->getResourceType()->getTool()->getToolResourceRight();
215
            // By default the rights are:
216
            // teacher: CRUD
217
            // student: read
218
            $readerMask = self::getReaderMask();
219
            $editorMask = self::getEditorMask();
220
221
            $resourceRight = new ResourceRight();
222
            $resourceRight
223
                ->setMask($editorMask)
224
                ->setRole(self::ROLE_CURRENT_COURSE_TEACHER)
225
            ;
226
            $rights[] = $resourceRight;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$rights was never initialized. Although not strictly required by PHP, it is generally a good practice to add $rights = array(); before regardless.
Loading history...
227
228
            $resourceRight = new ResourceRight();
229
            $resourceRight
230
                ->setMask($readerMask)
231
                ->setRole(self::ROLE_CURRENT_COURSE_STUDENT)
232
            ;
233
            $rights[] = $resourceRight;
234
        }
235
236
        // Asked mask
237
        $mask = new MaskBuilder();
238
        $mask->add($attribute);
239
        $askedMask = $mask->get();
240
241
        // Setting zend simple ACL
242
        $acl = new Acl();
243
244
        // Creating roles
245
        // @todo move this in a service
246
        $userRole = new Role('ROLE_USER');
247
        $teacher = new Role('ROLE_TEACHER');
248
        $student = new Role('ROLE_STUDENT');
249
        $currentTeacher = new Role(self::ROLE_CURRENT_COURSE_TEACHER);
250
        $currentStudent = new Role(self::ROLE_CURRENT_COURSE_STUDENT);
251
        $superAdmin = new Role('ROLE_SUPER_ADMIN');
252
        $admin = new Role('ROLE_ADMIN');
253
254
        // Adding roles to the ACL
255
        $acl
256
            ->addRole($userRole)
257
            ->addRole($student)
258
            ->addRole($teacher)
259
            ->addRole($currentStudent)
260
            ->addRole($currentTeacher, self::ROLE_CURRENT_COURSE_STUDENT)
261
            ->addRole($superAdmin)
262
            ->addRole($admin)
263
        ;
264
265
        // Adds a resource
266
        $resource = new SecurityResource($link);
267
        $acl->addResource($resource);
268
269
        // Check all the right this link has.
270
        // $roles = [];
271
        // Set rights from the ResourceRight
272
        foreach ($rights as $right) {
273
            //$roles[$right->getMask()] = $right->getRole();
274
            $acl->allow($right->getRole(), null, $right->getMask());
275
        }
276
277
        // var_dump($askedMask, $roles);
278
        // Role and permissions settings
279
        // Student can just view (read)
280
        //$acl->allow($student, null, self::getReaderMask());
281
282
        // Teacher can view/edit
283
        $acl->allow(
284
            $teacher,
285
            null,
286
            [
287
                self::getReaderMask(),
288
                self::getEditorMask(),
289
            ]
290
        );
291
292
        // Admin can do everything
293
        $acl->allow($admin);
294
        $acl->allow($superAdmin);
295
296
        foreach ($user->getRoles() as $role) {
297
            //var_dump($acl->isAllowed($role, $resource, $askedMask), $role);
298
            if ($acl->isAllowed($role, $resource, $askedMask)) {
299
                return true;
300
            }
301
        }
302
303
        //dump('not allowed to '.$attribute);
304
        return false;
305
    }
306
}
307