IssueController::getDeleteAttachment()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 3
Bugs 1 Features 1
Metric Value
c 3
b 1
f 1
dl 0
loc 18
ccs 0
cts 0
cp 0
rs 9.4285
cc 2
eloc 11
nc 2
nop 3
crap 6
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\Project;
13
14
use Illuminate\Http\Request;
15
use Illuminate\Http\Response;
16
use Tinyissue\Form\Comment as CommentForm;
17
use Tinyissue\Form\Issue as IssueForm;
18
use Tinyissue\Http\Controllers\Controller;
19
use Tinyissue\Http\Requests\FormRequest;
20
use Tinyissue\Model\Project;
21
use Tinyissue\Model\Project\Issue;
22
use Tinyissue\Model\Project\Issue\Attachment;
23
use Tinyissue\Model\Project\Issue\Comment;
24
use Tinyissue\Model\Tag;
25
use Tinyissue\Model\User\Activity as UserActivity;
26
27
/**
28
 * IssueController is the controller class for managing request related to projects issues.
29
 *
30
 * @author Mohamed Alsharaf <[email protected]>
31
 */
32
class IssueController extends Controller
33
{
34
    /**
35
     * Project issue index page (List project issues).
36
     *
37
     * @param Project     $project
38
     * @param Issue       $issue
39
     * @param CommentForm $form
40
     *
41
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
42
     */
43 16
    public function getIndex(Project $project, Issue $issue, CommentForm $form)
44
    {
45
        // Projects should be limited to issue-modify
46 16
        $projects = null;
47 16
        if (!$this->auth->guest() && $this->getLoggedUser()->permission('issue-modify')) {
48 13
            $projects = $this->getLoggedUser()->projects()->get();
49
        }
50
51 16
        return view('project.issue.index', [
52 16
            'issue'       => $issue,
53 16
            'project'     => $project,
54 16
            'commentForm' => $form,
55 16
            'sidebar'     => 'project',
56 16
            'projects'    => $projects,
57
        ]);
58
    }
59
60
    /**
61
     * Ajax: Assign new user to an issue.
62
     *
63
     * @param Issue   $issue
64
     * @param Request $request
65
     *
66
     * @return \Symfony\Component\HttpFoundation\Response
67
     */
68 1
    public function postAssign(Issue $issue, Request $request)
69
    {
70 1
        $response = ['status' => false];
71 1
        if ($issue->reassign((int) $request->input('user_id'), $this->getLoggedUser())) {
72 1
            $response['status'] = true;
73
        }
74
75 1
        return response()->json($response);
76
    }
77
78
    /**
79
     * Ajax: save comment.
80
     *
81
     * @param Comment $comment
82
     * @param Request $request
83
     *
84
     * @return \Symfony\Component\HttpFoundation\Response
85
     */
86 1
    public function postEditComment(Comment $comment, Request $request)
87
    {
88 1
        $body = '';
89 1
        if ($request->has('body')) {
90 1
            $comment->updateBody((string) $request->input('body'), $this->getLoggedUser());
91 1
            $body = \Html::format($comment->comment);
92
        }
93
94 1
        return response()->json(['text' => $body]);
95
    }
96
97
    /**
98
     * To add new comment to an issue.
99
     *
100
     * @param Project             $project
101
     * @param Issue               $issue
102
     * @param Comment             $comment
103
     * @param FormRequest\Comment $request
104
     *
105
     * @return \Illuminate\Http\RedirectResponse
106
     */
107 4
    public function postAddComment(Project $project, Issue $issue, Comment $comment, FormRequest\Comment $request)
108
    {
109 4
        $comment->setRelation('project', $project);
110 4
        $comment->setRelation('issue', $issue);
111 4
        $comment->setRelation('user', $this->getLoggedUser());
112 4
        $comment->createComment($request->all());
113
114 4
        return redirect($issue->to() . '#comment' . $comment->id)
115 4
            ->with('notice', trans('tinyissue.your_comment_added'));
116
    }
117
118
    /**
119
     * Ajax: to delete a comment.
120
     *
121
     * @param Comment $comment
122
     *
123
     * @return \Symfony\Component\HttpFoundation\Response
124
     */
125 1
    public function getDeleteComment(Comment $comment)
126
    {
127 1
        $comment->deleteComment($this->getLoggedUser());
128
129 1
        return response()->json(['status' => true]);
130
    }
131
132
    /**
133
     * New issue form.
134
     *
135
     * @param Project   $project
136
     * @param IssueForm $form
137
     *
138
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
139
     */
140 5
    public function getNew(Project $project, IssueForm $form)
141
    {
142 5
        return view('project.issue.new', [
143 5
            'project' => $project,
144 5
            'form'    => $form,
145 5
            'sidebar' => 'project',
146
        ]);
147
    }
148
149
    /**
150
     * To create a new issue.
151
     *
152
     * @param Project           $project
153
     * @param Issue             $issue
154
     * @param FormRequest\Issue $request
155
     *
156
     * @return \Illuminate\Http\RedirectResponse
157
     */
158 2
    public function postNew(Project $project, Issue $issue, FormRequest\Issue $request)
159
    {
160 2
        $issue->setRelation('project', $project);
161 2
        $issue->setRelation('user', $this->getLoggedUser());
162 2
        $issue->createIssue($request->all());
163
164 2
        return redirect($issue->to())
165 2
            ->with('notice', trans('tinyissue.issue_has_been_created'));
166
    }
167
168
    /**
169
     * Edit an existing issue form.
170
     *
171
     * @param Project   $project
172
     * @param Issue     $issue
173
     * @param IssueForm $form
174
     *
175
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
176
     */
177 2
    public function getEdit(Project $project, Issue $issue, IssueForm $form)
178
    {
179
        // Cannot edit closed issue
180 2
        if ($issue->status == Issue::STATUS_CLOSED) {
181 1
            return redirect($issue->to())
182 1
                ->with('notice', trans('tinyissue.cant_edit_closed_issue'));
183
        }
184
185 2
        return view('project.issue.edit', [
186 2
            'issue'   => $issue,
187 2
            'project' => $project,
188 2
            'form'    => $form,
189 2
            'sidebar' => 'project',
190
        ]);
191
    }
192
193
    /**
194
     * To update an existing issue details.
195
     *
196
     * @param Project           $project
197
     * @param Issue             $issue
198
     * @param FormRequest\Issue $request
199
     *
200
     * @return \Illuminate\Http\RedirectResponse
201
     */
202 1
    public function postEdit(Project $project, Issue $issue, FormRequest\Issue $request)
203
    {
204
        // Delete the issue
205 1
        if ($request->has('delete-issue')) {
206
            $issue->delete();
207
208
            return redirect($project->to())
209
                ->with('notice', trans('tinyissue.issue_has_been_deleted'));
210
        }
211
212 1
        $issue->setRelation('project', $project);
213 1
        $issue->setRelation('updatedBy', $this->getLoggedUser());
214 1
        $issue->updateIssue($request->all());
215
216 1
        return redirect($issue->to())
217 1
            ->with('notice', trans('tinyissue.issue_has_been_updated'));
218
    }
219
220
    /**
221
     * To close or reopen an issue.
222
     *
223
     * @param Project $project
224
     * @param Issue   $issue
225
     * @param int     $status
226
     *
227
     * @return \Illuminate\Http\RedirectResponse
228
     */
229 2
    public function getClose(Project $project, Issue $issue, $status = 0)
230
    {
231 2
        if ($status == 0) {
232 2
            $message = trans('tinyissue.issue_has_been_closed');
233
        } else {
234 1
            $message = trans('tinyissue.issue_has_been_reopened');
235
        }
236
237 2
        $issue->setRelation('project', $project);
238 2
        $issue->changeStatus($status, $this->getLoggedUser());
239
240 2
        return redirect($issue->to())
241 2
            ->with('notice', $message);
242
    }
243
244
    /**
245
     * To upload an attachment file.
246
     *
247
     * @param Project    $project
248
     * @param Attachment $attachment
249
     * @param Request    $request
250
     *
251
     * @return \Symfony\Component\HttpFoundation\Response
252
     */
253 3
    public function postUploadAttachment(Project $project, Attachment $attachment, Request $request)
254
    {
255
        try {
256 3
            if (!$this->getLoggedUser()->permission('project-all')) {
257
                abort(404);
258
            }
259
260 3
            $attachment->upload($request->all(), $project, $this->getLoggedUser());
261
262
            $response = [
263
                'upload' => [
264
                    [
265 3
                        'name'   => $attachment->filename,
266 3
                        'size'   => $attachment->filesize,
267 3
                        'fileId' => $attachment->id,
268
                    ],
269
                ],
270
            ];
271
        } catch (\Exception $exception) {
272
            $file = $request->file('upload');
273
274
            $response = [
275
                'status' => false,
276
                'name'   => $file->getClientOriginalName(),
277
                'error'  => $exception->getMessage(),
278
                'trace'  => $exception->getTraceAsString(),
279
            ];
280
        }
281
282 3
        return response()->json($response);
283
    }
284
285
    /**
286
     * Ajax: to remove an attachment file.
287
     *
288
     * @param Project    $project
289
     * @param Attachment $attachment
290
     * @param Request    $request
291
     *
292
     * @return \Symfony\Component\HttpFoundation\Response
293
     */
294 1
    public function postRemoveAttachment(Project $project, Attachment $attachment, Request $request)
295
    {
296 1
        $attachment->remove($request->all(), $project, $this->getLoggedUser());
297
298 1
        return response()->json(['status' => true]);
299
    }
300
301
    /**
302
     * Delete attachment.
303
     *
304
     * @param Project    $project
305
     * @param Issue      $issue
306
     * @param Attachment $attachment
307
     *
308
     * @return \Illuminate\Http\RedirectResponse
309
     */
310
    public function getDeleteAttachment(Project $project, Issue $issue, Attachment $attachment)
311
    {
312
        $path = config('filesystems.disks.local.root')
313
            . '/' . config('tinyissue.uploads_dir')
314
            . '/' . $project->id
315
            . '/' . $attachment->upload_token;
316
        try {
317
            $attachment->deleteFile($path, $attachment->filename);
318
        } catch (\Exception $e) {
319
            // For now error of removing the file from the storage is ignored.
320
            // File might not be in server, error is not important.
321
            // No permission to delete file, this will creates orphan file.
322
        }
323
        $attachment->delete();
324
325
        return redirect($issue->to())
326
            ->with('notice', trans('tinyissue.attachment_has_been_deleted'));
327
    }
328
329
    /**
330
     * Display an attachment file such as image.
331
     *
332
     * @param Project    $project
333
     * @param Issue      $issue
334
     * @param Attachment $attachment
335
     * @param Request    $request
336
     *
337
     * @return Response
338
     */
339 2
    public function getDisplayAttachment(Project $project, Issue $issue, Attachment $attachment, Request $request)
340
    {
341 2
        $issue->setRelation('project', $project);
342 2
        $attachment->setRelation('issue', $issue);
343
344 2
        $path    = config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
345 2
        $storage = \Storage::disk('local');
346 2
        $length  = $storage->size($path);
347 2
        $time    = $storage->lastModified($path);
348 2
        $type    = $storage->getDriver()->getMimetype($path);
349
350 2
        $response = new Response();
351 2
        $response->setEtag(md5($time . $path));
352 2
        $response->setExpires(new \DateTime('@' . ($time + 60)));
353 2
        $response->setLastModified(new \DateTime('@' . $time));
354 2
        $response->setPublic();
355 2
        $response->setStatusCode(200);
356
357 2
        $response->header('Content-Type', $type);
358 2
        $response->header('Content-Length', $length);
359 2
        $response->header('Content-Disposition', 'inline; filename="' . $attachment->filename . '"');
360 2
        $response->header('Cache-Control', 'must-revalidate');
361
362 2
        if ($response->isNotModified($request)) {
363
            // Return empty response if not modified
364
            return $response;
365
        }
366
367
        // Return file if first request / modified
368 2
        $response->setContent($storage->get($path));
369
370 2
        return $response;
371
    }
372
373
    /**
374
     * Download an attachment file.
375
     *
376
     * @param Project    $project
377
     * @param Issue      $issue
378
     * @param Attachment $attachment
379
     *
380
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
381
     */
382 1
    public function getDownloadAttachment(Project $project, Issue $issue, Attachment $attachment)
383
    {
384 1
        $issue->setRelation('project', $project);
385 1
        $attachment->setRelation('issue', $issue);
386
387 1
        $path = config('filesystems.disks.local.root') . '/' . config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
388
389 1
        return response()->download($path, $attachment->filename);
390
    }
391
392
    /**
393
     * Ajax: move an issue to another project.
394
     *
395
     * @param Issue   $issue
396
     * @param Request $request
397
     *
398
     * @return \Symfony\Component\HttpFoundation\Response
399
     */
400 1
    public function postChangeProject(Issue $issue, Request $request)
401
    {
402 1
        $issue->changeProject((int) $request->input('project_id'));
403
404 1
        return response()->json(['status' => true, 'url' => $issue->to()]);
405
    }
406
407
    /**
408
     * Ajax: change status of an issue.
409
     *
410
     * @param Issue   $issue
411
     * @param Request $request
412
     *
413
     * @return \Symfony\Component\HttpFoundation\Response
414
     */
415 1
    public function postChangeKanbanTag(Issue $issue, Request $request)
416
    {
417 1
        $newTag = Tag::find((int) $request->input('newtag'));
418 1
        $oldTag = Tag::find((int) $request->input('oldtag'));
419
420 1
        $issue->changeKanbanTag($newTag, $oldTag);
421
422 1
        return response()->json(['status' => true, 'issue' => $issue->id]);
423
    }
424
425
    /**
426
     * Ajax: returns comments for an issue.
427
     *
428
     * @param Project $project
429
     * @param Issue   $issue
430
     *
431
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\Vie
432
     */
433 8
    public function getIssueComments(Project $project, Issue $issue)
434
    {
435
        $issue->attachments->each(function (Attachment $attachment) use ($issue) {
436
            $attachment->setRelation('issue', $issue);
437 8
        });
438 8
        $activities = $issue->commentActivities()->with('activity', 'user', 'comment', 'assignTo',
439 8
            'comment.attachments')->get();
440
        $activities->each(function (UserActivity $activity) use ($issue) {
441 8
            $activity->setRelation('issue', $issue);
442 8
        });
443
444 8
        return view('project.issue.partials.activities', [
445 8
            'noData'     => trans('tinyissue.no_comments'),
446 8
            'activities' => $activities,
447 8
            'project'    => $project,
448 8
            'issue'      => $issue,
449
        ]);
450
    }
451
452
    /**
453
     * Ajax: returns activities for an issue excluding comments.
454
     *
455
     * @param Project $project
456
     * @param Issue   $issue
457
     *
458
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\Vie
459
     */
460 1
    public function getIssueActivity(Project $project, Issue $issue)
461
    {
462 1
        $activities = $issue->generalActivities()->with('activity', 'user', 'assignTo')->get();
463 1
        $activities->each(function (UserActivity $activity) use ($issue) {
464 1
            $activity->setRelation('issue', $issue);
465 1
        });
466
467 1
        return view('project.issue.partials.activities', [
468 1
            'noData'     => trans('tinyissue.no_activities'),
469 1
            'activities' => $activities,
470 1
            'project'    => $project,
471 1
            'issue'      => $issue,
472
        ]);
473
    }
474
}
475