Completed
Branch develop (82845d)
by Mohamed
03:11
created

Permission::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
/*
4
 * This file is part of the Tinyissue package.
5
 *
6
 * (c) Mohamed Alsharaf <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Tinyissue\Http\Middleware;
13
14
use Closure;
15
use Tinyissue\Model\User;
16
use Illuminate\Http\Request;
17
use Illuminate\Routing\Route;
18
use Tinyissue\Model\Project as ProjectModel;
19
use Tinyissue\Model\Permission as PermissionModel;
20
use Illuminate\Database\Eloquent\Model as ModelAbstract;
21
22
/**
23
 * Permission is a Middleware class to for checking if current user has the permission to access the request.
24
 *
25
 * @author Mohamed Alsharaf <[email protected]>
26
 */
27
class Permission extends MiddlewareAbstract
28
{
29
    /**
30
     * List of permissions that can be accessed by public users.
31
     *
32
     * @var array
33
     */
34
    protected $publicAccess = [
35
        'issue-view',
36
    ];
37
38
    /**
39
     * Ordered list of contexts.
40
     *
41
     * @var array
42
     */
43
    protected $contexts = [
44
        'comment',
45
        'attachment',
46
        'issue',
47
        'project',
48
    ];
49
50
    /**
51
     * Handle an incoming request.
52
     *
53
     * @param Request  $request
54
     * @param \Closure $next
55
     *
56
     * @return mixed
57
     */
58
    public function handle(Request $request, Closure $next)
59
    {
60
        $permission = $this->getPermission($request);
61
62
        // Can't access if public project disabled or user does not have access
63
        if (!$this->isInPublicProjectContext($request, $permission) && !$this->canAccess($request, $permission)) {
64 45
            abort(401);
65
        }
66 45
67 45
        return $next($request);
68
    }
69
70
    /**
71
     * Whether or not the current context is in public project.
72
     *
73
     * @param Request $request
74
     * @param string  $permission
75
     *
76
     * @return bool
77 44
     */
78
    protected function isInPublicProjectContext(Request $request, $permission)
79 44
    {
80
        /** @var ProjectModel|null $project */
81
        $project         = $request->route()->getParameter('project');
82 44
        $isPublicEnabled = app('tinyissue.settings')->isPublicProjectsEnabled();
83 8
        $isPublicAccess  = in_array($permission, $this->publicAccess);
84
        $isPublicProject = $project instanceof ProjectModel && $project->isPublic();
85
86 40
        return $isPublicEnabled && $isPublicAccess && $isPublicProject;
87
    }
88
89
    /**
90
     * Whether or not the user can access the current context.
91
     *
92
     * @param Request $request
93
     * @param string  $permission
94
     *
95
     * @return bool
96
     */
97 44
    protected function canAccess(Request $request, $permission)
98
    {
99
        try {
100 44
            $user = $this->getLoggedUser();
101 44
        } catch (\Exception $e) {
102 44
            return false;
103 44
        }
104
105 44
        return !(!$user->permission($permission) || !$this->canAccessContext($user, $request->route(), $permission));
0 ignored issues
show
Documentation introduced by
$request->route() is of type object|string, but the function expects a object<Illuminate\Routing\Route>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
106
    }
107
108
    /**
109
     * Whether or not the user has a valid permission in current context
110
     * e.g. can access the issue or the project.
111
     *
112
     * @param User   $user
113
     * @param Route  $route
114
     * @param string $permission
115
     *
116 44
     * @return bool
117
     */
118 44
    public function canAccessContext(User $user, Route $route, $permission)
119
    {
120 44
        // Can access all projects
121
        if ($user->permission(PermissionModel::PERM_PROJECT_ALL)) {
122
            return true;
123
        }
124
125
        // Can access the current context
126
        $context = $this->getCurrentContext($route);
127
        if (is_null($context)) {
128
            abort(500, 'Permission middleware added to un-supported context.');
129
        }
130
        $action  = $permission == PermissionModel::PERM_ISSUE_MODIFY ? 'canEdit' : 'canView';
131
132
        return $context->$action($user);
133 41
    }
134
135
    /**
136 41
     * Return the model object of the current context.
137 36
     * We check the lowest ( Comment ) first, to the highest ( Project ).
138
     *
139
     * @param Route $route
140
     *
141 10
     * @return ModelAbstract|null
142 10
     */
143
    protected function getCurrentContext(Route $route)
144
    {
145 10
        foreach ($this->contexts as $context) {
146
            $parameter = $route->getParameter($context);
147 10
            if ($parameter instanceof ModelAbstract) {
148
                return $parameter;
149
            }
150
        }
151
152
        return null;
153
    }
154
155
    /**
156
     * Returns the permission defined in route action.
157
     *
158 10
     * @param Request $request
159
     *
160 10
     * @return mixed
161 10
     */
162 10
    protected function getPermission(Request $request)
163 10
    {
164
        $actions = $request->route()->getAction();
165
166
        return $actions['permission'];
167
    }
168
}
169