Completed
Branch develop (ad0fd2)
by Mohamed
03:54
created

ProjectController::getEdit()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 2
cts 2
cp 1
rs 9.4285
cc 1
eloc 5
nc 1
nop 2
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\Controllers;
13
14
use Illuminate\Http\Request;
15
use Tinyissue\Form\FilterIssue as FilterForm;
16
use Tinyissue\Form\Note as NoteForm;
17
use Tinyissue\Form\Project as Form;
18
use Tinyissue\Http\Requests\FormRequest;
19
use Tinyissue\Model\Project;
20
use Tinyissue\Model\Project\Issue;
21
use Tinyissue\Model\Project\Note;
22
use Tinyissue\Services\Exporter;
23
24
/**
25
 * ProjectController is the controller class for managing request related to a project.
26
 *
27
 * @author Mohamed Alsharaf <[email protected]>
28
 */
29
class ProjectController extends Controller
30
{
31
    /**
32
     * Display activity for a project.
33
     *
34
     * @param Project $project
35
     *
36
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
37
     */
38
    public function getIndex(Project $project)
39 12
    {
40
        $activities = $project->activities()
41 12
            ->with('activity', 'issue', 'user', 'assignTo', 'comment', 'note')
42 12
            ->orderBy('users_activity.created_at', 'DESC')
43 12
            ->take(10);
44 12
45
        // Internal project and logged user can see created only
46
        if ($project->isPrivateInternal() && $this->getLoggedUser()->isUser()) {
47 12
            $activities->join('projects_issues', 'projects_issues.id', '=', 'item_id');
48
            $activities->where('created_by', '=', $this->getLoggedUser()->id);
49
        }
50
51
        return view('project.index', [
52 12
            'tabs'       => $this->projectMainViewTabs($project, 'index'),
53 12
            'project'    => $project,
54 12
            'active'     => 'activity',
55 12
            'activities' => $activities->get(),
56 12
            'sidebar'    => 'project',
57 12
        ]);
58
    }
59
60
    /**
61
     * Display issues for a project.
62
     *
63
     * @param FilterForm $filterForm
64
     * @param Request    $request
65
     * @param Project    $project
66
     * @param int        $status
67
     *
68
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
69
     */
70
    public function getIssues(FilterForm $filterForm, Request $request, Project $project, $status = Issue::STATUS_OPEN)
71 2
    {
72
        if ($project->isPrivateInternal() && $this->getLoggedUser()->isUser()) {
73 2
            $request['created_by'] = $this->getLoggedUser()->id;
74
        }
75
        $active                = $status == Issue::STATUS_OPEN ? 'open_issue' : 'closed_issue';
76 2
        $issues                = $project->listIssues($status, $request->all());
77 2
78
        return view('project.index', [
79 2
            'tabs'       => $this->projectMainViewTabs($project, 'issues', $issues, $status),
0 ignored issues
show
Documentation introduced by
$status is of type integer, but the function expects a boolean.

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...
80 2
            'project'    => $project,
81 2
            'active'     => $active,
82 2
            'issues'     => $issues,
83 2
            'sidebar'    => 'project',
84 2
            'filterForm' => $filterForm,
85 2
        ]);
86
    }
87
88
    /**
89
     * Display issues assigned to current user for a project.
90
     *
91
     * @param Project $project
92
     *
93
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
94
     */
95 View Code Duplication
    public function getAssigned(Project $project)
1 ignored issue
show
Duplication introduced by
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...
96 1
    {
97
        $issues = $project->listAssignedOrCreatedIssues($this->getLoggedUser());
0 ignored issues
show
Bug introduced by
It seems like $this->getLoggedUser() can be null; however, listAssignedOrCreatedIssues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
98 1
99
        return view('project.index', [
100 1
            'tabs'    => $this->projectMainViewTabs($project, 'assigned', $issues),
101 1
            'project' => $project,
102 1
            'active'  => 'issue_assigned_to_you',
103 1
            'issues'  => $issues,
104 1
            'sidebar' => 'project',
105 1
        ]);
106
    }
107
108
    /**
109
     * Display issues created to current user for a project.
110
     *
111
     * @param Project $project
112
     *
113
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
114
     */
115 View Code Duplication
    public function getCreated(Project $project)
1 ignored issue
show
Duplication introduced by
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...
116
    {
117
        $issues = $project->listAssignedOrCreatedIssues($this->getLoggedUser());
0 ignored issues
show
Bug introduced by
It seems like $this->getLoggedUser() can be null; however, listAssignedOrCreatedIssues() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
118
119
        return view('project.index', [
120
            'tabs'    => $this->projectMainViewTabs($project, 'created', $issues),
121
            'project' => $project,
122
            'active'  => 'issue_created_by_you',
123
            'issues'  => $issues,
124
            'sidebar' => 'project',
125
        ]);
126
    }
127
128
    /**
129
     * Display notes for a project.
130
     *
131
     * @param Project  $project
132
     * @param NoteForm $form
133
     *
134
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
135
     */
136 View Code Duplication
    public function getNotes(Project $project, NoteForm $form)
1 ignored issue
show
Duplication introduced by
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...
137 7
    {
138
        $notes = $project->notes()->with('createdBy')->get();
139 7
140
        return view('project.index', [
141 7
            'tabs'     => $this->projectMainViewTabs($project, 'notes', $notes),
142 7
            'project'  => $project,
143 7
            'active'   => 'notes',
144 7
            'notes'    => $notes,
145 7
            'sidebar'  => 'project',
146 7
            'noteForm' => $form,
147 7
        ]);
148
    }
149
150
    /**
151
     * @param Project $project
152
     * @param string  $view
153
     * @param null    $data
154
     * @param bool    $status
155
     *
156
     * @return array
157
     */
158
    protected function projectMainViewTabs(Project $project, $view, $data = null, $status = false)
159 22
    {
160
        $user              = $this->getLoggedUser();
161 22
        $isLoggedIn        = !$this->auth->guest();
162 22
        $isUser            = $isLoggedIn && $user->isUser();
163 22
        $isInternalProject = $project->isPrivateInternal();
164 22
165 22
        if ($view === 'note') {
166
            $notesCount = !is_null($data) ? $data->count() : 0;
167 22
        } else {
168 2
            $notesCount = $project->notes()->count();
169 2
        }
170 2
171
        if ($view === 'issues') {
172 1
            if ($status == Issue::STATUS_OPEN) {
173 2
                $closedIssuesCount = $project->closedIssuesCount($user)->count();
174
                $openIssuesCount   = !is_null($data) ? $data->count() : 0;
175
            } else {
176 20
                $closedIssuesCount = !is_null($data) ? $data->count() : 0;
177 20
                $openIssuesCount   = $project->openIssuesCount($user)->count();
178
            }
179
        } else {
180 22
            $openIssuesCount   = $project->openIssuesCount($user)->count();
181 22
            $closedIssuesCount = $project->closedIssuesCount($user)->count();
182 22
        }
183 22
184
        $tabs   = [];
185 22
        $tabs[] = [
186 22
            'url'  => $project->to(),
187 22
            'page' => 'activity',
188 22
        ];
189
        $tabs[] = [
190 22
            'url'    => $project->to('issues'),
191 22
            'page'   => 'open_issue',
192 22
            'prefix' => $openIssuesCount,
193 22
        ];
194
        $tabs[] = [
195 22
            'url'    => $project->to('issues') . '/0',
196 21
            'page'   => 'closed_issue',
197 20
            'prefix' => $closedIssuesCount,
198 20
        ];
199
        if ($isLoggedIn && (!$isInternalProject || (!$isUser && $isInternalProject))) {
200 1
            if ($view !== 'assigned') {
201
                $method              = $isUser ? 'createdIssuesCount' : 'assignedIssuesCount';
202
                $assignedIssuesCount = $this->getLoggedUser()->$method($project->id);
203 21
            } else {
204 21
                $assignedIssuesCount = !is_null($data) ? $data->count() : 0;
205 21
            }
206 21
207
            $tabs[] = [
208
                'url'    => $project->to($isUser ? 'created' : 'assigned'),
209 22
                'page'   => ($isUser ? 'issue_created_by_you' : 'issue_assigned_to_you'),
210 22
                'prefix' => $assignedIssuesCount,
211 22
            ];
212 22
        }
213
        $tabs[] = [
214
            'url'    => $project->to('notes'),
215 22
            'page'   => 'notes',
216
            'prefix' => $notesCount,
217
        ];
218
219
        return $tabs;
220
    }
221
222
    /**
223
     * Edit the project.
224
     *
225
     * @param Project $project
226 3
     * @param Form    $form
227
     *
228 3
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
229 3
     */
230 3
    public function getEdit(Project $project, Form $form)
231 3
    {
232
        return view('project.edit', [
233
            'form'    => $form,
234
            'project' => $project,
235
            'sidebar' => 'project',
236
        ]);
237
    }
238
239
    /**
240
     * To update project details.
241
     *
242
     * @param Project             $project
243 3
     * @param FormRequest\Project $request
244
     *
245
     * @return \Illuminate\Http\RedirectResponse
246 3
     */
247 1
    public function postEdit(Project $project, FormRequest\Project $request)
248
    {
249 1
        // Delete the project
250 1
        if ($request->has('delete-project')) {
251
            $project->delete();
252
253 2
            return redirect('projects')
254
                ->with('notice', trans('tinyissue.project_has_been_deleted'));
255 2
        }
256 2
257
        $project->update($request->all());
258
259
        return redirect($project->to())
260
            ->with('notice', trans('tinyissue.project_has_been_updated'));
261
    }
262
263
    /**
264
     * Ajax: returns list of users that are not in the project.
265
     *
266 1
     * @param Project $project
267
     *
268 1
     * @return \Symfony\Component\HttpFoundation\Response
269
     */
270 1
    public function getInactiveUsers(Project $project)
271
    {
272
        $users = $project->usersNotIn();
273
274
        return response()->json($users);
275
    }
276
277
    /**
278
     * Ajax: add user to the project.
279
     *
280
     * @param Project $project
281 1
     * @param Request $request
282
     *
283 1
     * @return \Symfony\Component\HttpFoundation\Response
284 1
     */
285 1 View Code Duplication
    public function postAssign(Project $project, Request $request)
0 ignored issues
show
Duplication introduced by
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...
286 1
    {
287
        $status = false;
288
        if ($request->has('user_id')) {
289 1
            $project->assignUser((int) $request->input('user_id'));
290
            $status = true;
291
        }
292
293
        return response()->json(['status' => $status]);
294
    }
295
296
    /**
297
     * Ajax: remove user from the project.
298
     *
299
     * @param Project $project
300 1
     * @param Request $request
301
     *
302 1
     * @return \Symfony\Component\HttpFoundation\Response
303 1
     */
304 1 View Code Duplication
    public function postUnassign(Project $project, Request $request)
0 ignored issues
show
Duplication introduced by
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...
305 1
    {
306
        $status = false;
307
        if ($request->has('user_id')) {
308 1
            $project->unassignUser((int) $request->input('user_id'));
309
            $status = true;
310
        }
311
312
        return response()->json(['status' => $status]);
313
    }
314
315
    /**
316
     * To add a new note to the project.
317
     *
318
     * @param Project          $project
319
     * @param Note             $note
320 2
     * @param FormRequest\Note $request
321
     *
322 2
     * @return \Illuminate\Http\RedirectResponse
323 2
     */
324 2
    public function postAddNote(Project $project, Note $note, FormRequest\Note $request)
325
    {
326 2
        $note->setRelation('project', $project);
327
        $note->setRelation('createdBy', $this->getLoggedUser());
328
        $note->createNote($request->all());
329
330
        return redirect($note->to())->with('notice', trans('tinyissue.your_note_added'));
331
    }
332
333
    /**
334
     * Ajax: To update project note.
335
     *
336
     * @param Project $project
337
     * @param Note    $note
338 1
     * @param Request $request
339
     *
340 1
     * @return \Symfony\Component\HttpFoundation\Response
341 1
     */
342 1
    public function postEditNote(Project $project, Project\Note $note, Request $request)
343 1
    {
344
        $body = '';
345 1
        if ($request->has('body')) {
346
            $note->setRelation('project', $project);
347
            $note->updateBody($request->input('body'), $this->getLoggedUser());
0 ignored issues
show
Bug introduced by
It seems like $request->input('body') targeting Illuminate\Http\Request::input() can also be of type array; however, Tinyissue\Model\Traits\P...CrudTrait::updateBody() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
Bug introduced by
It seems like $this->getLoggedUser() can be null; however, updateBody() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
348 1
349
            $body = \Html::format($note->body);
350
        }
351
352
        return response()->json(['status' => true, 'text' => $body]);
353
    }
354
355
    /**
356
     * Ajax: to delete a project note.
357
     *
358
     * @param Project $project
359 1
     * @param Note    $note
360
     *
361 1
     * @return \Symfony\Component\HttpFoundation\Response
362
     */
363 1
    public function getDeleteNote(Project $project, Project\Note $note)
0 ignored issues
show
Unused Code introduced by
The parameter $project is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
364
    {
365
        $note->deleteNote($this->getLoggedUser());
0 ignored issues
show
Bug introduced by
It seems like $this->getLoggedUser() can be null; however, deleteNote() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
366
367
        return response()->json(['status' => true]);
368
    }
369
370
    /**
371
     * Ajax: generate the issues export file.
372
     *
373
     * @param Project  $project
374
     * @param Exporter $exporter
375 4
     * @param Request  $request
376
     *
377
     * @return \Symfony\Component\HttpFoundation\Response
378 4
     */
379 4
    public function postExportIssues(Project $project, Exporter $exporter, Request $request)
380 4
    {
381 4
        // Generate export file
382
        $info = $exporter->exportFile(
383
            'Project\Issue',
384
            $request->input('format', Exporter::TYPE_CSV),
0 ignored issues
show
Bug introduced by
It seems like $request->input('format'...ces\Exporter::TYPE_CSV) targeting Illuminate\Http\Request::input() can also be of type array; however, Tinyissue\Services\Exporter::exportFile() does only seem to accept string, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
385 4
            $request->all()
386 4
        );
387 4
388 4
        // Download link
389
        $link = link_to(
390
            $project->to('download_export/' . $info['file']),
391 4
            trans('tinyissue.download_export'),
392 4
            ['class' => 'btn btn-link']
393 4
        );
394 4
395 4
        return response()->json([
396
            'link'  => $link,
397
            'title' => $info['title'],
398
            'file'  => $info['file'],
399
            'ext'   => $info['ext'],
400
        ]);
401
    }
402
403
    /**
404
     * Download and then delete an export file.
405
     *
406
     * @param Project $project
407 4
     * @param string  $file
408
     *
409
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
410 4
     */
411
    public function getDownloadExport(Project $project, $file)
0 ignored issues
show
Unused Code introduced by
The parameter $project is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
412
    {
413 4
        // Filter out any characters that are not in pattern
414
        $file = preg_replace('/[^a-z0-9\_\.]/mi', '', $file);
415
416
        // Download export
417
        return response()->download(storage_path('exports/' . $file), $file)->deleteFileAfterSend(true);
418
    }
419
}
420