Issues (125)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

app/Form/Issue.php (1 issue)

Upgrade to new PHP Analysis Engine

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\Form;
13
14
use Illuminate\Support\Collection;
15
use Tinyissue\Model;
16
17
/**
18
 * Issue is a class to defines fields & rules for add/edit issue form.
19
 *
20
 * @author Mohamed Alsharaf <[email protected]>
21
 */
22
class Issue extends FormAbstract
23
{
24
    /**
25
     * An instance of project model.
26
     *
27
     * @var Model\Project
28
     */
29
    protected $project;
30
31
    /**
32
     * Collection of all tags.
33
     *
34
     * @var \Illuminate\Database\Eloquent\Collection
35
     */
36
    protected $tags = null;
37
38
    /**
39
     * Is issue readonly.
40
     *
41
     * @var bool
42
     */
43
    protected $readOnly = false;
44
45
    /**
46
     * @param string $type
47
     *
48
     * @return \Illuminate\Database\Eloquent\Collection
49
     */
50 9 View Code Duplication
    protected function getTags($type)
0 ignored issues
show
This method seems to be duplicated in your project.

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.

Loading history...
51
    {
52 9
        if ($this->tags === null) {
53 9
            $this->tags = (new Model\Tag())->getGroupTags();
54
        }
55
56 9
        return $this->tags->where('name', $type)->first()->tags;
57
    }
58
59
    /**
60
     * Returns an array of tags to be used as the selectable options.
61
     *
62
     * @param string $type
63
     *
64
     * @return array
65
     */
66 9
    protected function getSelectableTags($type = null)
67
    {
68 9
        $currentTag = $this->getIssueTag($type);
69
70 9
        if ($currentTag->id && (!$currentTag->canView() || $this->readOnly)) {
71 1
            $tags = [$currentTag];
72 9
        } elseif ($this->readOnly) {
73 1
            $tags = [];
74
        } else {
75 9
            $tags = $this->getTags($type);
76
        }
77
78 9
        return $this->generateTagRadioButtonOptions($tags, $type);
79
    }
80
81
    /**
82
     * Get issue tag for specific type/group.
83
     *
84
     * @param string $type
85
     *
86
     * @return Model\Tag
87
     */
88 9
    protected function getIssueTag($type)
89
    {
90 9
        if ($this->isEditing()) {
91 4
            $groupId     = $this->getTags($type)->first()->parent_id;
92 4
            $selectedTag = $this->getModel()->tags->where('parent_id', $groupId);
93
94 4
            if ($selectedTag->count() > 0) {
95 1
                return $selectedTag->last();
96
            }
97
        }
98
99 9
        return new Model\Tag();
100
    }
101
102
    /**
103
     * @param array $params
104
     *
105
     * @return void
106
     */
107 8
    public function setup(array $params)
108
    {
109 8
        $this->project = $params['project'];
110 8
        if (!empty($params['issue'])) {
111 4
            $this->editingModel($params['issue']);
112 4
            $this->readOnly = $this->getModel()->hasReadOnlyTag($this->getLoggedUser());
113
        }
114 8
    }
115
116
    /**
117
     * @return array
118
     */
119 6
    public function actions()
120
    {
121 6
        $actions = [];
122
123
        // Check if issue is in readonly tag
124 6
        if (!$this->readOnly) {
125
            $actions = [
126 6
                'submit' => $this->isEditing() ? 'update_issue' : 'create_issue',
127
            ];
128
129 6
            if ($this->isEditing() && $this->getLoggedUser()->permission(Model\Permission::PERM_ISSUE_MODIFY)) {
130 2
                $actions['delete'] = [
131 2
                    'type'         => 'danger_submit',
132 2
                    'label'        => trans('tinyissue.delete_something', ['name' => '#' . $this->getModel()->id]),
133 2
                    'class'        => 'close-issue',
134 2
                    'name'         => 'delete-issue',
135 2
                    'data-message' => trans('tinyissue.delete_issue_confirm'),
136
                ];
137
            }
138
        }
139
140 6
        return $actions;
141
    }
142
143
    /**
144
     * @return array
145
     */
146 8
    public function fields()
147
    {
148 8
        $issueModify = $this->getLoggedUser()->permission('issue-modify');
149
150 8
        $fields = [];
151 8
        $fields += $this->readOnlyMessage();
152 8
        $fields += $this->fieldTitle();
153 8
        $fields += $this->fieldBody();
154 8
        $fields += $this->fieldTag('type');
155
156
        // Only on creating new issue
157 8
        if (!$this->isEditing()) {
158 5
            $fields += $this->fieldUpload();
159
        }
160
161
        // Show fields for users with issue modify permission
162 8
        if ($issueModify) {
163 8
            $fields += $this->issueModifyFields();
164
        }
165
166 8
        return $fields;
167
    }
168
169
    /**
170
     * Return a list of fields for users with issue modify permission.
171
     *
172
     * @return array
173
     */
174 8
    protected function issueModifyFields()
175
    {
176 8
        $fields = [];
177
178 8
        $fields['internal_status'] = [
179
            'type' => 'legend',
180
        ];
181
182
        // Status tags
183 8
        $fields += $this->fieldTag('status');
184
185
        // Assign users
186 8
        $fields += $this->fieldAssignedTo();
187
188
        // Quotes
189 8
        $fields += $this->fieldTimeQuote();
190
191
        // Resolution tags
192 8
        $fields += $this->fieldResolutionTags();
193
194 8
        return $fields;
195
    }
196
197
    /**
198
     * Returns message about read only issue.
199
     *
200
     * @return array
201
     */
202 8
    protected function readOnlyMessage()
203
    {
204 8
        $field = [];
205
206 8
        if ($this->readOnly) {
207
            $field = [
208
                'readonly' => [
209 1
                    'type'  => 'plaintext',
210 1
                    'label' => ' ',
211 1
                    'value' => '<div class="alert alert-warning">' . trans('tinyissue.readonly_issue_message') . '</div>',
212
                ],
213
            ];
214
        }
215
216 8
        return $field;
217
    }
218
219
    /**
220
     * Returns title field.
221
     *
222
     * @return array
223
     */
224 9
    protected function fieldTitle()
225
    {
226
        return [
227
            'title' => [
228
                'type'  => 'text',
229
                'label' => 'title',
230 9
            ],
231
        ];
232
    }
233
234
    /**
235
     * Returns body field.
236
     *
237
     * @return array
238
     */
239 9
    protected function fieldBody()
240
    {
241
        return [
242
            'body' => [
243
                'type'  => 'textarea',
244
                'label' => 'issue',
245 9
            ],
246
        ];
247
    }
248
249
    /**
250
     * Returns tag field.
251
     *
252
     * @param string $type
253
     * @param array  $prepend
254
     *
255
     * @return array
256
     */
257 9
    protected function fieldTag($type, array $prepend = [])
258
    {
259 9
        $options = $prepend + $this->getSelectableTags($type);
260 9
        $name    = 'tag_' . $type;
261
262
        return [
263
            $name => [
264 9
                'label'  => $type,
265 9
                'type'   => 'radioButton',
266 9
                'radios' => $options,
267 9
                'check'  => $this->getIssueTag($type)->id,
268
            ],
269
        ];
270
    }
271
272
    /**
273
     * Returns tags field.
274
     *
275
     * @return array
276
     */
277 8
    protected function fieldResolutionTags()
278
    {
279 8
        return $this->fieldTag('resolution', [
280 8
            trans('tinyissue.none') => [
281
                'name'      => 'tag_resolution',
282
                'value'     => 0,
283
                'data-tags' => 0,
284
                'color'     => '#62CFFC',
285 8
            ],
286
        ]);
287
    }
288
289
    /**
290
     * Returns assigned to field.
291
     *
292
     * @return array
293
     */
294 8
    protected function fieldAssignedTo()
295
    {
296
        return [
297
            'assigned_to' => [
298 8
                'type'    => 'select',
299 8
                'label'   => 'assigned_to',
300 8
                'options' => [0 => ''] + $this->project->usersCanFixIssue()->get()->lists('fullname', 'id')->all(),
301 8
                'value'   => (int) $this->project->default_assignee,
302
            ],
303
        ];
304
    }
305
306
    /**
307
     * Returns upload field.
308
     *
309
     * @return array
310
     */
311 6
    protected function fieldUpload()
312
    {
313 6
        $user                      = $this->getLoggedUser();
314 6
        $fields                    = $this->projectUploadFields('upload', $this->project, $user);
315 6
        $fields['upload']['label'] = 'attachments';
316
317 6
        return $fields;
318
    }
319
320
    /**
321
     * Returns time quote field.
322
     *
323
     * @return array
324
     */
325 8
    protected function fieldTimeQuote()
326
    {
327
        $fields = [
328
            'time_quote' => [
329 8
                'type'     => 'groupField',
330 8
                'label'    => 'quote',
331
                'fields'   => [
332
                    'h'    => [
333 8
                        'type'          => 'number',
334 8
                        'append'        => trans('tinyissue.hours'),
335 8
                        'value'         => $this->extractQuoteValue('h'),
336 8
                        'addGroupClass' => 'col-sm-5 col-md-5 col-lg-4',
337
                    ],
338
                    'm'    => [
339 8
                        'type'          => 'number',
340 8
                        'append'        => trans('tinyissue.minutes'),
341 8
                        'value'         => $this->extractQuoteValue('m'),
342 8
                        'addGroupClass' => 'col-sm-5 col-md-5 col-lg-4',
343
                    ],
344
                    'lock' => [
345 8
                        'type'          => 'checkboxButton',
346 8
                        'label'         => '',
347
                        'noLabel'       => true,
348 8
                        'class'         => 'eee',
349 8
                        'addGroupClass' => 'sss col-sm-12 col-md-12 col-lg-4',
350
                        'checkboxes'    => [
351
                            'Lock Quote' => [
352 8
                                'value'     => 1,
353 8
                                'data-tags' => 1,
354 8
                                'color'     => 'red',
355 8
                                'checked'   => $this->isEditing() && $this->getModel()->isQuoteLocked(),
356
                            ],
357
                        ],
358
                        'grouped'       => true,
359
                    ],
360
                ],
361 8
                'addClass' => 'row issue-quote',
362 8
            ],
363
        ];
364
365
        // If user does not have access to lock quote, then remove the field
366 8
        if (!$this->getLoggedUser()->permission(Model\Permission::PERM_ISSUE_LOCK_QUOTE)) {
367 3
            unset($fields['time_quote']['fields']['lock']);
368
369
            // If quote is locked then remove quote fields
370 3
            if ($this->isEditing() && $this->getModel()->isQuoteLocked()) {
371 1
                return [];
372
            }
373
        }
374
375 8
        return $fields;
376
    }
377
378
    /**
379
     * @return array
380
     */
381 7
    public function rules()
382
    {
383
        $rules = [
384 7
            'title' => 'required|max:200',
385
            'body'  => 'required',
386
        ];
387
388 7
        return $rules;
389
    }
390
391
    /**
392
     * @return string
393
     */
394
    public function getRedirectUrl()
395
    {
396
        if ($this->isEditing()) {
397
            return $this->getModel()->to('edit');
398
        }
399
400
        return 'project/' . $this->project->id . '/issue/new';
401
    }
402
403
    /**
404
     * Extract number of hours, or minutes, or seconds from a quote.
405
     *
406
     * @param string $part
407
     *
408
     * @return float|int
409
     */
410 8
    protected function extractQuoteValue($part)
411
    {
412 8
        if ($this->getModel() instanceof Model\Project\Issue) {
413 4
            $seconds = $this->getModel()->time_quote;
414 4
            if ($part === 'h') {
415 4
                return floor($seconds / 3600);
416
            }
417
418 4
            if ($part === 'm') {
419 4
                return ($seconds / 60) % 60;
420
            }
421
        }
422
423 5
        return 0;
424
    }
425
426
    /**
427
     * Returns an array structured for radio button element.
428
     *
429
     * @param Collection|array $tags
430
     * @param string           $type
431
     *
432
     * @return array
433
     */
434 9
    protected function generateTagRadioButtonOptions($tags, $type)
435
    {
436 9
        $options = [];
437
438 9
        if (is_array($tags) || $tags instanceof Collection) {
439 9
            foreach ($tags as $tag) {
440 9
                $options[ucwords($tag->name)] = [
441 9
                    'name'      => 'tag_' . $type,
442 9
                    'value'     => $tag->id,
443 9
                    'data-tags' => $tag->id,
444 9
                    'color'     => $tag->bgcolor,
445
                ];
446
            }
447
        }
448
449 9
        return $options;
450
    }
451
}
452