This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
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\Model; |
||
13 | |||
14 | use Illuminate\Database\Eloquent\Collection; |
||
15 | use Illuminate\Database\Eloquent\Model; |
||
16 | use Tinyissue\Contracts\Model\AccessControl; |
||
17 | use URL; |
||
18 | |||
19 | /** |
||
20 | * Project is model class for projects. |
||
21 | * |
||
22 | * @author Mohamed Alsharaf <[email protected]> |
||
23 | * |
||
24 | * @property int $id |
||
25 | * @property string $name |
||
26 | * @property int $status |
||
27 | * @property int $default_assignee |
||
28 | * @property int $private |
||
29 | * @property int $openIssuesCount |
||
30 | * @property int $closedIssuesCount |
||
31 | * @property int $closedIssuesCount |
||
32 | * @property Collection $issues |
||
33 | * @property Collection $issuesByUser |
||
34 | * @property Collection $users |
||
35 | * @property Collection $projectUsers |
||
36 | * @property Collection $activities |
||
37 | * @property Collection $notes |
||
38 | * @property Collection $kanbanTags |
||
39 | */ |
||
40 | class Project extends Model implements AccessControl |
||
41 | { |
||
42 | use Traits\CountAttributeTrait, |
||
43 | Traits\Project\CountTrait, |
||
44 | Traits\Project\FilterTrait, |
||
45 | Traits\Project\SortTrait, |
||
46 | Traits\Project\RelationTrait, |
||
47 | Traits\Project\CrudTrait, |
||
48 | Traits\Project\QueryTrait; |
||
49 | |||
50 | /** |
||
51 | * Project private & user role can see their own issues only. |
||
52 | * |
||
53 | * @var int |
||
54 | */ |
||
55 | const INTERNAL_YES = 2; |
||
56 | |||
57 | /** |
||
58 | * Project not public to view and create issue. |
||
59 | * |
||
60 | * @var int |
||
61 | */ |
||
62 | const PRIVATE_YES = 1; |
||
63 | |||
64 | /** |
||
65 | * Project public to view and create issue. |
||
66 | * |
||
67 | * @var int |
||
68 | */ |
||
69 | const PRIVATE_NO = 0; |
||
70 | |||
71 | /** |
||
72 | * All projects. |
||
73 | * |
||
74 | * @var int |
||
75 | */ |
||
76 | const PRIVATE_ALL = -1; |
||
77 | |||
78 | /** |
||
79 | * Project status Open. |
||
80 | * |
||
81 | * @var int |
||
82 | */ |
||
83 | const STATUS_OPEN = 1; |
||
84 | |||
85 | /** |
||
86 | * Project status Archived. |
||
87 | * |
||
88 | * @var int |
||
89 | */ |
||
90 | const STATUS_ARCHIVED = 0; |
||
91 | |||
92 | /** |
||
93 | * Timestamp enabled. |
||
94 | * |
||
95 | * @var bool |
||
96 | */ |
||
97 | public $timestamps = true; |
||
98 | |||
99 | /** |
||
100 | * Name of database table. |
||
101 | * |
||
102 | * @var string |
||
103 | */ |
||
104 | protected $table = 'projects'; |
||
105 | |||
106 | /** |
||
107 | * List of allowed columns to be used in $this->fill(). |
||
108 | * |
||
109 | * @var array |
||
110 | */ |
||
111 | protected $fillable = ['name', 'default_assignee', 'status', 'private']; |
||
112 | |||
113 | /** |
||
114 | * List of HTML classes for each status. |
||
115 | * |
||
116 | * @var array |
||
117 | */ |
||
118 | protected $attrClassNames = [ |
||
119 | self::PRIVATE_NO => 'note', |
||
120 | self::PRIVATE_YES => 'info', |
||
121 | self::INTERNAL_YES => 'primary', |
||
122 | ]; |
||
123 | |||
124 | /** |
||
125 | * List of statuses names. |
||
126 | * |
||
127 | * @var array |
||
128 | */ |
||
129 | protected $statusesNames = [ |
||
130 | self::PRIVATE_NO => 'public', |
||
131 | self::PRIVATE_YES => 'private', |
||
132 | self::INTERNAL_YES => 'internal', |
||
133 | ]; |
||
134 | |||
135 | /** |
||
136 | * Generate a URL for the active project. |
||
137 | * |
||
138 | * @param string $url |
||
139 | * |
||
140 | * @return string |
||
141 | */ |
||
142 | 45 | public function to($url = '') |
|
143 | { |
||
144 | 45 | return URL::to('project/' . $this->id . (($url) ? '/' . $url : '')); |
|
145 | } |
||
146 | |||
147 | /** |
||
148 | * Returns the aggregate value of number of open issues in the project. |
||
149 | * |
||
150 | * @return int |
||
151 | */ |
||
152 | 5 | public function getOpenIssuesCountAttribute() |
|
153 | { |
||
154 | 5 | return $this->getCountAttribute('openIssuesCount'); |
|
155 | } |
||
156 | |||
157 | /** |
||
158 | * Returns the aggregate value of number of closed issues in the project. |
||
159 | * |
||
160 | * @return int |
||
161 | */ |
||
162 | 1 | public function getClosedIssuesCountAttribute() |
|
163 | { |
||
164 | 1 | return $this->getCountAttribute('closedIssuesCount'); |
|
165 | } |
||
166 | |||
167 | /** |
||
168 | * Set default assignee attribute. |
||
169 | * |
||
170 | * @param int $value |
||
171 | * |
||
172 | * @return $this |
||
173 | */ |
||
174 | 54 | public function setDefaultAssigneeAttribute($value) |
|
175 | { |
||
176 | 54 | if (!empty($value)) { |
|
177 | 35 | $this->attributes['default_assignee'] = (int) $value; |
|
178 | } |
||
179 | |||
180 | 54 | return $this; |
|
181 | } |
||
182 | |||
183 | /** |
||
184 | * Returns the aggregate value of number of issues in the project. |
||
185 | * |
||
186 | * @return int |
||
187 | */ |
||
188 | public function getIssuesCountAttribute() |
||
189 | { |
||
190 | return $this->getCountAttribute('issuesCount'); |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Get total issues total quote time. |
||
195 | * |
||
196 | * @return int |
||
197 | */ |
||
198 | 3 | public function getTotalQuote() |
|
199 | { |
||
200 | 3 | $total = 0; |
|
201 | 3 | foreach ($this->issues as $issue) { |
|
202 | 3 | $total += $issue->time_quote; |
|
203 | } |
||
204 | |||
205 | 3 | return $total; |
|
206 | } |
||
207 | |||
208 | /** |
||
209 | * Calculate the progress (open & closed issues). |
||
210 | * |
||
211 | * @return float|int |
||
212 | */ |
||
213 | 1 | public function getProgress() |
|
214 | { |
||
215 | 1 | $total = $this->openIssuesCount + $this->closedIssuesCount; |
|
216 | 1 | $progress = 100; |
|
217 | 1 | if ($total > 0) { |
|
218 | 1 | $progress = (float) ($this->closedIssuesCount / $total) * 100; |
|
219 | } |
||
220 | 1 | $progressInt = (int) $progress; |
|
221 | 1 | if ($progressInt > 0) { |
|
222 | 1 | $progress = number_format($progress, 2); |
|
223 | 1 | $fraction = $progress - $progressInt; |
|
224 | 1 | if ($fraction === 0.0) { |
|
225 | 1 | $progress = $progressInt; |
|
226 | } |
||
227 | } |
||
228 | |||
229 | 1 | return $progress; |
|
230 | } |
||
231 | |||
232 | /** |
||
233 | * Whether or not a user is member of the project. |
||
234 | * |
||
235 | * @param int $userId |
||
236 | * |
||
237 | * @return bool |
||
238 | */ |
||
239 | 10 | public function isMember($userId) |
|
240 | { |
||
241 | 10 | return $this->user($userId)->count() > 0; |
|
242 | } |
||
243 | |||
244 | /** |
||
245 | * Whether or not the project is private. |
||
246 | * |
||
247 | * @return bool |
||
248 | */ |
||
249 | 2 | public function isPrivate() |
|
250 | { |
||
251 | 2 | return (int) $this->private === self::PRIVATE_YES; |
|
252 | } |
||
253 | |||
254 | /** |
||
255 | * Whether or not the project is public. |
||
256 | * |
||
257 | * @return bool |
||
258 | */ |
||
259 | 34 | public function isPublic() |
|
260 | { |
||
261 | 34 | return (int) $this->private === self::PRIVATE_NO; |
|
262 | } |
||
263 | |||
264 | /** |
||
265 | * Whether or not the project is private internal. |
||
266 | * |
||
267 | * @return bool |
||
268 | */ |
||
269 | 29 | public function isPrivateInternal() |
|
270 | { |
||
271 | 29 | return (int) $this->private === self::INTERNAL_YES; |
|
272 | } |
||
273 | |||
274 | /** |
||
275 | * Returns project status as string name. |
||
276 | * |
||
277 | * @return string |
||
278 | */ |
||
279 | 2 | public function getStatusAsName() |
|
280 | { |
||
281 | 2 | if (array_key_exists((int) $this->private, $this->statusesNames)) { |
|
282 | 2 | return $this->statusesNames[(int) $this->private]; |
|
283 | } |
||
284 | |||
285 | return ''; |
||
286 | } |
||
287 | |||
288 | /** |
||
289 | * Returns the class name to be used for project status. |
||
290 | * |
||
291 | * @return string |
||
292 | */ |
||
293 | 2 | public function getStatusClass() |
|
294 | { |
||
295 | 2 | if (array_key_exists((int) $this->private, $this->attrClassNames)) { |
|
296 | 2 | return $this->attrClassNames[(int) $this->private]; |
|
297 | } |
||
298 | |||
299 | return ''; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Whether or not a user can access the project. |
||
304 | * |
||
305 | * @param User $user |
||
306 | * |
||
307 | * @return bool |
||
308 | */ |
||
309 | 3 | public function canView(User $user) |
|
310 | { |
||
311 | // Is member of the project |
||
312 | if ( |
||
313 | 3 | ($this->isPublic() && app('tinyissue.settings')->isPublicProjectsEnabled()) || |
|
314 | 3 | $this->isMember($user->id) |
|
315 | ) { |
||
316 | 1 | return true; |
|
317 | } |
||
318 | |||
319 | 3 | return false; |
|
320 | } |
||
321 | |||
322 | /** |
||
323 | * Whether a user can edit the project. |
||
324 | * |
||
325 | * @param User $user |
||
326 | * |
||
327 | * @return bool |
||
328 | */ |
||
329 | 1 | public function canEdit(User $user) |
|
330 | { |
||
331 | 1 | return $user->permission(Permission::PERM_PROJECT_MODIFY) || $user->permission(Permission::PERM_PROJECT_ALL); |
|
332 | } |
||
333 | |||
334 | /** |
||
335 | * @param string $permission |
||
336 | * @param User $user |
||
337 | * |
||
338 | * @return bool |
||
339 | */ |
||
340 | 4 | View Code Duplication | public function can($permission, User $user) |
0 ignored issues
–
show
|
|||
341 | { |
||
342 | $editPermissions = [ |
||
343 | 4 | Permission::PERM_PROJECT_CREATE, |
|
344 | 4 | Permission::PERM_PROJECT_MODIFY, |
|
345 | ]; |
||
346 | |||
347 | 4 | if (in_array($permission, $editPermissions)) { |
|
348 | 1 | return $this->canEdit($user); |
|
349 | } |
||
350 | |||
351 | 3 | return $this->canView($user); |
|
352 | } |
||
353 | } |
||
354 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.