Failed Conditions
Push — master ( 276992...d29638 )
by Adrien
06:52
created

Acl::getLastDenialMessage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Acl;
6
7
use Application\Acl\Assertion\All;
8
use Application\Acl\Assertion\ExpenseClaimStatusIsNew;
9
use Application\Acl\Assertion\IsMyself;
10
use Application\Acl\Assertion\IsOwner;
11
use Application\Acl\Assertion\IsRecipient;
12
use Application\Acl\Assertion\StatusIsNew;
13
use Application\Model\AbstractModel;
14
use Application\Model\Account;
15
use Application\Model\AccountingDocument;
16
use Application\Model\Bookable;
17
use Application\Model\BookableMetadata;
18
use Application\Model\BookableTag;
19
use Application\Model\Booking;
20
use Application\Model\Category;
21
use Application\Model\Country;
22
use Application\Model\ExpenseClaim;
23
use Application\Model\Image;
24
use Application\Model\License;
25
use Application\Model\Message;
26
use Application\Model\Transaction;
27
use Application\Model\User;
28
use Application\Model\UserTag;
29
use Doctrine\Common\Util\ClassUtils;
30
31
class Acl extends \Zend\Permissions\Acl\Acl
32
{
33
    /**
34
     * The message explaining the last denial
35
     *
36
     * @var null|string
37
     */
38
    private $message;
39
40 15
    public function __construct()
41
    {
42
        // Each role is strictly "stronger" than the last one
43 15
        $this->addRole(User::ROLE_ANONYMOUS);
44 15
        $this->addRole(User::ROLE_BOOKING_ONLY, User::ROLE_ANONYMOUS);
45 15
        $this->addRole(User::ROLE_INDIVIDUAL, User::ROLE_BOOKING_ONLY);
46 15
        $this->addRole(User::ROLE_MEMBER, User::ROLE_INDIVIDUAL);
47 15
        $this->addRole(User::ROLE_RESPONSIBLE, User::ROLE_MEMBER);
48 15
        $this->addRole(User::ROLE_ADMINISTRATOR, User::ROLE_RESPONSIBLE);
49
50 15
        $bookable = new ModelResource(Bookable::class);
51 15
        $bookableMetadata = new ModelResource(BookableMetadata::class);
52 15
        $bookableTag = new ModelResource(BookableTag::class);
53 15
        $booking = new ModelResource(Booking::class);
54 15
        $image = new ModelResource(Image::class);
55 15
        $license = new ModelResource(License::class);
56 15
        $user = new ModelResource(User::class);
57 15
        $userTag = new ModelResource(UserTag::class);
58 15
        $country = new ModelResource(Country::class);
59 15
        $account = new ModelResource(Account::class);
60 15
        $accountingDocument = new ModelResource(AccountingDocument::class);
61 15
        $category = new ModelResource(Category::class);
62 15
        $expenseClaim = new ModelResource(ExpenseClaim::class);
63 15
        $message = new ModelResource(Message::class);
64 15
        $transaction = new ModelResource(Transaction::class);
65
66 15
        $this->addResource($bookable);
67 15
        $this->addResource($bookableMetadata);
68 15
        $this->addResource($bookableTag);
69 15
        $this->addResource($booking);
70 15
        $this->addResource($image);
71 15
        $this->addResource($license);
72 15
        $this->addResource($user);
73 15
        $this->addResource($userTag);
74 15
        $this->addResource($country);
75 15
        $this->addResource($account);
76 15
        $this->addResource($accountingDocument);
77 15
        $this->addResource($category);
78 15
        $this->addResource($expenseClaim);
79 15
        $this->addResource($message);
80 15
        $this->addResource($transaction);
81
82 15
        $this->allow(User::ROLE_ANONYMOUS, [$country, $bookable, $bookableMetadata, $bookableTag, $image, $license, $category], ['read']);
83 15
        $this->allow(User::ROLE_ANONYMOUS, $user, ['create']);
84
85 15
        $this->allow(User::ROLE_BOOKING_ONLY, $booking, ['create', 'read', 'update']);
86
87 15
        $this->allow(User::ROLE_INDIVIDUAL, $user, ['read']);
88 15
        $this->allow(User::ROLE_INDIVIDUAL, $user, ['update'], new IsMyself());
89 15
        $this->allow(User::ROLE_INDIVIDUAL, [$account, $expenseClaim], ['create']);
90 15
        $this->allow(User::ROLE_INDIVIDUAL, [$expenseClaim], ['read'], new IsOwner());
91 15
        $this->allow(User::ROLE_INDIVIDUAL, [$expenseClaim], ['update', 'delete'], new All(new IsOwner(), new StatusIsNew()));
92 15
        $this->allow(User::ROLE_INDIVIDUAL, [$accountingDocument], ['create'], new ExpenseClaimStatusIsNew());
93 15
        $this->allow(User::ROLE_INDIVIDUAL, [$accountingDocument], ['read'], new IsOwner());
94 15
        $this->allow(User::ROLE_INDIVIDUAL, [$accountingDocument], ['update', 'delete'], new All(new IsOwner(), new ExpenseClaimStatusIsNew()));
95 15
        $this->allow(User::ROLE_INDIVIDUAL, [$account], ['read', 'update'], new IsOwner());
96 15
        $this->allow(User::ROLE_INDIVIDUAL, $message, ['read'], new IsRecipient());
97
98 15
        $this->allow(User::ROLE_MEMBER, $user, ['update'], new IsOwner());
99
100 15
        $this->allow(User::ROLE_RESPONSIBLE, [$transaction, $account, $category], ['read']);
101 15
        $this->allow(User::ROLE_RESPONSIBLE, [$expenseClaim, $accountingDocument], ['read', 'update']);
102 15
        $this->allow(User::ROLE_RESPONSIBLE, [$user], ['update']);
103 15
        $this->allow(User::ROLE_RESPONSIBLE, [$userTag], ['create', 'read', 'update', 'delete']);
104 15
        $this->allow(User::ROLE_RESPONSIBLE, [$bookable, $bookableMetadata, $bookableTag, $image, $license], ['create', 'update', 'delete']);
105
106 15
        $this->allow(User::ROLE_ADMINISTRATOR, [$transaction, $account, $category], ['create', 'update', 'delete']);
107 15
    }
108
109
    /**
110
     * Return whether the current user is allowed to do something
111
     *
112
     * This should be the main method to do all ACL checks.
113
     *
114
     * @param AbstractModel $model
115
     * @param string $privilege
116
     *
117
     * @return bool
118
     */
119 15
    public function isCurrentUserAllowed(AbstractModel $model, string $privilege): bool
120
    {
121 15
        $resource = new ModelResource($this->getClass($model), $model);
122
123 15
        $role = $this->getCurrentRole();
124
125 15
        $isAllowed = $this->isAllowed($role, $resource, $privilege);
126
127 15
        $this->message = $this->buildMessage($resource, $privilege, $role, $isAllowed);
128
129 15
        return $isAllowed;
130
    }
131
132 15
    private function getClass(AbstractModel $resource): string
133
    {
134 15
        return ClassUtils::getRealClass(get_class($resource));
135
    }
136
137 15
    private function getCurrentRole(): string
138
    {
139 15
        $user = User::getCurrent();
140 15
        if (!$user) {
141 4
            return 'anonymous';
142
        }
143
144 15
        return $user->getRole();
145
    }
146
147 15
    private function buildMessage($resource, ?string $privilege, string $role, bool $isAllowed): ?string
148
    {
149 15
        if ($isAllowed) {
150 14
            return null;
151
        }
152
153 8
        if ($resource instanceof ModelResource) {
154 8
            $resource = $resource->getName();
155
        }
156
157 8
        $user = User::getCurrent() ? 'User "' . User::getCurrent()->getLogin() . '"' : 'Non-logged user';
158 8
        $privilege = $privilege === null ? 'NULL' : $privilege;
159
160 8
        return "$user with role $role is not allowed on resource \"$resource\" with privilege \"$privilege\"";
161
    }
162
163
    /**
164
     * Returns the message explaining the last denial, if any
165
     *
166
     * @return null|string
167
     */
168 2
    public function getLastDenialMessage(): ?string
169
    {
170 2
        return $this->message;
171
    }
172
}
173