Passed
Push — dependabot/npm_and_yarn/tar-7.... ( ae31d2...265b94 )
by
unknown
21:55 queued 09:58
created

UserVoter::voteOnAttribute()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 48
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
eloc 23
nc 10
nop 3
dl 0
loc 48
rs 7.3166
c 1
b 0
f 0

How to fix   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
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Security\Authorization\Voter;
8
9
use Chamilo\CoreBundle\Entity\Message;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\Entity\UserRelUser;
12
use Doctrine\ORM\EntityManagerInterface;
13
use Symfony\Bundle\SecurityBundle\Security;
14
use Symfony\Component\HttpFoundation\RequestStack;
15
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
16
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
17
use Symfony\Component\Security\Core\User\UserInterface;
18
19
/**
20
 * @extends Voter<'CREATE'|'VIEW'|'EDIT'|'DELETE', UserVoter>
21
 */
22
class UserVoter extends Voter
23
{
24
    public const CREATE = 'CREATE';
25
    public const VIEW = 'VIEW';
26
    public const EDIT = 'EDIT';
27
    public const DELETE = 'DELETE';
28
29
    public function __construct(
30
        private Security $security,
31
        private EntityManagerInterface $entityManager,
32
        private RequestStack $requestStack
33
    ) {}
34
35
    protected function supports(string $attribute, $subject): bool
36
    {
37
        $options = [
38
            self::CREATE,
39
            self::VIEW,
40
            self::EDIT,
41
            self::DELETE,
42
        ];
43
44
        // if the attribute isn't one we support, return false
45
        if (!\in_array($attribute, $options, true)) {
46
            return false;
47
        }
48
49
        return $subject instanceof User;
50
    }
51
52
    protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token): bool
53
    {
54
        /** @var User $currentUser */
55
        $currentUser = $token->getUser();
56
57
        if (!$currentUser instanceof UserInterface) {
58
            return false;
59
        }
60
61
        if ($this->security->isGranted('ROLE_ADMIN')) {
62
            return true;
63
        }
64
65
        /** @var User $user */
66
        $user = $subject;
67
68
        if (self::EDIT === $attribute) {
69
            // Only the owner can edit private data
70
            return (int) $currentUser->getId() === (int) $user->getId();
71
        }
72
73
        if (self::VIEW === $attribute) {
74
            if ((int) $currentUser->getId() === (int) $user->getId()) {
75
                return true;
76
            }
77
78
            if ($user->hasFriendWithRelationType($currentUser, UserRelUser::USER_RELATION_TYPE_FRIEND)) {
79
                return true;
80
            }
81
82
            $friendsOfFriends = $currentUser->getFriendsOfFriends();
83
            if (\in_array($user, $friendsOfFriends, true)) {
84
                return true;
85
            }
86
87
            if (
88
                $user->hasFriendWithRelationType($currentUser, UserRelUser::USER_RELATION_TYPE_BOSS)
89
                || $user->isFriendWithMeByRelationType($currentUser, UserRelUser::USER_RELATION_TYPE_BOSS)
90
            ) {
91
                return true;
92
            }
93
94
            if ($this->haveSharedMessages($currentUser, $user)) {
95
                return true;
96
            }
97
        }
98
99
        return false;
100
    }
101
102
    private function isFromSocialPage(): bool
0 ignored issues
show
Unused Code introduced by
The method isFromSocialPage() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
103
    {
104
        $request = $this->requestStack->getCurrentRequest();
105
        if ($request) {
106
            $pageOrigin = $request->query->get('page_origin');
107
108
            return 'social' === $pageOrigin;
109
        }
110
111
        return false;
112
    }
113
114
    private function haveSharedMessages(User $currentUser, User $targetUser): bool
115
    {
116
        $messageRepository = $this->entityManager->getRepository(Message::class);
117
118
        return $messageRepository->usersHaveSharedMessages($currentUser, $targetUser);
119
    }
120
}
121