Completed
Push — master ( 195b94...7a36f1 )
by Mohamed
04:50
created

IssueController::getAddComment()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 10
ccs 1
cts 1
cp 1
rs 9.4285
cc 1
eloc 7
nc 1
nop 4
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\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 18
    public function getIndex(Project $project, Issue $issue, CommentForm $form)
44
    {
45
        // Projects should be limited to issue-modify
46 1
        $projects = null;
47 18
        if (!$this->auth->guest() && $this->getLoggedUser()->permission('issue-modify')) {
48 18
            $projects = $this->getLoggedUser()->projects()->get();
49 18
        }
50 18
51 18
        return view('project.issue.index', [
52 18
            'issue'       => $issue,
53
            'project'     => $project,
54
            'commentForm' => $form,
55 18
            'sidebar'     => 'project',
56 18
            'projects'    => $projects,
57 15
        ]);
58
    }
59
60 18
    /**
61 18
     * Ajax: Assign new user to an issue.
62 18
     *
63 18
     * @param Issue   $issue
64 18
     * @param Request $request
65 18
     *
66 18
     * @return \Symfony\Component\HttpFoundation\Response
67
     */
68
    public function postAssign(Issue $issue, Request $request)
69
    {
70
        $response = ['status' => false];
71
        if ($issue->reassign((int) $request->input('user_id'), $this->getLoggedUser())) {
72
            $response['status'] = true;
73
        }
74
75
        return response()->json($response);
76
    }
77
78 1
    /**
79
     * Ajax: save comment.
80 1
     *
81 1
     * @param Comment $comment
82 1
     * @param Request $request
83
     *
84
     * @return \Symfony\Component\HttpFoundation\Response
85 1
     */
86
    public function postEditComment(Comment $comment, Request $request)
87
    {
88
        $body = '';
89
        if ($request->has('body')) {
90
            $comment->updateBody((string) $request->input('body'), $this->getLoggedUser());
91
            $body = \Html::format($comment->comment);
92
        }
93
94
        return response()->json(['text' => $body]);
95
    }
96 1
97
    /**
98 1
     * To add new comment to an issue.
99 1
     *
100 1
     * @param Project             $project
101 1
     * @param Issue               $issue
102
     * @param Comment             $comment
103
     * @param FormRequest\Comment $request
104 1
     *
105
     * @return \Illuminate\Http\RedirectResponse
106
     */
107
    public function postAddComment(Project $project, Issue $issue, Comment $comment, FormRequest\Comment $request)
108
    {
109
        $comment->setRelation('project', $project);
110
        $comment->setRelation('issue', $issue);
111
        $comment->setRelation('user', $this->getLoggedUser());
112
        $comment->createComment($request->all());
113
114
        return redirect($issue->to() . '#comment' . $comment->id)
115
            ->with('notice', trans('tinyissue.your_comment_added'));
116
    }
117 4
118
    /**
119 4
     * Ajax: to delete a comment.
120 4
     *
121 4
     * @param Comment $comment
122 4
     *
123
     * @return \Symfony\Component\HttpFoundation\Response
124 4
     */
125 4
    public function getDeleteComment(Comment $comment)
126
    {
127
        $comment->deleteComment($this->getLoggedUser());
128
129
        return response()->json(['status' => true]);
130
    }
131
132
    /**
133
     * New issue form.
134
     *
135 1
     * @param Project   $project
136
     * @param IssueForm $form
137 1
     *
138
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
139 1
     */
140
    public function getNew(Project $project, IssueForm $form)
141
    {
142
        return view('project.issue.new', [
143
            'project' => $project,
144
            'form'    => $form,
145
            'sidebar' => 'project',
146
        ]);
147
    }
148
149
    /**
150 5
     * To create a new issue.
151
     *
152 5
     * @param Project           $project
153 5
     * @param Issue             $issue
154 5
     * @param FormRequest\Issue $request
155 5
     *
156
     * @return \Illuminate\Http\RedirectResponse
157
     */
158
    public function postNew(Project $project, Issue $issue, FormRequest\Issue $request)
159
    {
160
        $issue->setRelation('project', $project);
161
        $issue->setRelation('user', $this->getLoggedUser());
162
        $issue->createIssue($request->all());
163
164
        return redirect($issue->to())
165
            ->with('notice', trans('tinyissue.issue_has_been_created'));
166
    }
167
168 2
    /**
169
     * Edit an existing issue form.
170 2
     *
171 2
     * @param Project   $project
172 2
     * @param Issue     $issue
173
     * @param IssueForm $form
174 2
     *
175 2
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
176
     */
177
    public function getEdit(Project $project, Issue $issue, IssueForm $form)
178
    {
179
        // Cannot edit closed issue
180
        if ($issue->status == Issue::STATUS_CLOSED) {
181
            return redirect($issue->to())
182
                ->with('notice', trans('tinyissue.cant_edit_closed_issue'));
183
        }
184
185
        return view('project.issue.edit', [
186
            'issue'   => $issue,
187 2
            'project' => $project,
188
            'form'    => $form,
189
            'sidebar' => 'project',
190 2
        ]);
191 1
    }
192 1
193
    /**
194
     * To update an existing issue details.
195 2
     *
196 2
     * @param Project           $project
197 2
     * @param Issue             $issue
198 2
     * @param FormRequest\Issue $request
199 2
     *
200
     * @return \Illuminate\Http\RedirectResponse
201
     */
202
    public function postEdit(Project $project, Issue $issue, FormRequest\Issue $request)
203
    {
204
        // Delete the issue
205
        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
        $issue->setRelation('updatedBy', $this->getLoggedUser());
214 1
        $issue->updateIssue($request->all());
215 1
216 1
        return redirect($issue->to())
217
            ->with('notice', trans('tinyissue.issue_has_been_updated'));
218 1
    }
219 1
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
    public function getClose(Project $project, Issue $issue, $status = 0)
230
    {
231 2
        if ($status == 0) {
232
            $message = trans('tinyissue.issue_has_been_closed');
233 2
        } else {
234 2
            $message = trans('tinyissue.issue_has_been_reopened');
235
        }
236 1
237
        $issue->setRelation('project', $project);
238
        $issue->changeStatus($status, $this->getLoggedUser());
239 2
240 2
        return redirect($issue->to())
241
            ->with('notice', $message);
242 2
    }
243 2
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
    public function postUploadAttachment(Project $project, Attachment $attachment, Request $request)
254
    {
255 3
        try {
256
            if (!$this->getLoggedUser()->permission('project-all')) {
257
                abort(404);
258 3
            }
259
260
            $attachment->upload($request->all(), $project, $this->getLoggedUser());
261
262 3
            $response = [
263
                'upload' => [
264
                    [
265
                        'name'   => $attachment->filename,
266
                        'size'   => $attachment->filesize,
267 3
                        'fileId' => $attachment->id,
268 3
                    ],
269 3
                ],
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
        return response()->json($response);
283
    }
284 3
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
    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 1
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 2
            . '/' . config('tinyissue.uploads_dir')
314
            . '/' . $project->id
315 2
            . '/' . $attachment->upload_token;
316 2
        try {
317
            $attachment->deleteFile($path, $attachment->filename);
318 2
        } catch (\Exception $e) {
319 2
            // For now error of removing the file from the storage is ignored.
320 2
            // File might not be in server, error is not important.
321 2
            // No permission to delete file, this will creates orphan file.
322 2
        }
323
        $attachment->delete();
324 2
325 2
        return redirect($issue->to())
326 2
            ->with('notice', trans('tinyissue.attachment_has_been_deleted'));
327 2
    }
328 2
329 2
    /**
330
     * Display an attachment file such as image.
331 2
     *
332 2
     * @param Project    $project
333 2
     * @param Issue      $issue
334 2
     * @param Attachment $attachment
335
     * @param Request    $request
336 2
     *
337
     * @return Response
338
     */
339
    public function getDisplayAttachment(Project $project, Issue $issue, Attachment $attachment, Request $request)
340
    {
341
        $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
        $storage = \Storage::disk('local');
346
        $length  = $storage->size($path);
347
        $time    = $storage->lastModified($path);
348
        $type    = $storage->getDriver()->getMimetype($path);
349
350
        $response = new Response();
351
        $response->setEtag(md5($time . $path));
352
        $response->setExpires(new \DateTime('@' . ($time + 60)));
353
        $response->setLastModified(new \DateTime('@' . $time));
354
        $response->setPublic();
355
        $response->setStatusCode(200);
356 1
357
        $response->header('Content-Type', $type);
358 1
        $response->header('Content-Length', $length);
359 1
        $response->header('Content-Disposition', 'inline; filename="' . $attachment->filename . '"');
360
        $response->header('Cache-Control', 'must-revalidate');
361 1
362
        if ($response->isNotModified($request)) {
363 1
            // Return empty response if not modified
364
            return $response;
365
        }
366
367
        // Return file if first request / modified
368
        $response->setContent($storage->get($path));
369
370
        return $response;
371
    }
372
373
    /**
374 1
     * Download an attachment file.
375
     *
376 1
     * @param Project    $project
377
     * @param Issue      $issue
378 1
     * @param Attachment $attachment
379
     *
380
     * @return \Symfony\Component\HttpFoundation\BinaryFileResponse
381
     */
382
    public function getDownloadAttachment(Project $project, Issue $issue, Attachment $attachment)
383
    {
384
        $issue->setRelation('project', $project);
385
        $attachment->setRelation('issue', $issue);
386
387
        $path = config('filesystems.disks.local.root') . '/' . config('tinyissue.uploads_dir') . '/' . $issue->project_id . '/' . $attachment->upload_token . '/' . $attachment->filename;
388
389
        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
    public function postChangeProject(Issue $issue, Request $request)
401
    {
402
        $issue->changeProject((int) $request->input('project_id'));
403
404
        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
    public function postChangeKanbanTag(Issue $issue, Request $request)
416
    {
417
        $newTag = Tag::find((int) $request->input('newtag'));
418
        $oldTag = Tag::find((int) $request->input('oldtag'));
419
420
        $issue->changeKanbanTag($newTag, $oldTag);
421
422
        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
    public function getIssueComments(Project $project, Issue $issue)
434
    {
435
        $issue->attachments->each(function (Attachment $attachment) use ($issue) {
436
            $attachment->setRelation('issue', $issue);
437
        });
438
        $activities = $issue->commentActivities()->with('activity', 'user', 'comment', 'assignTo',
439
            'comment.attachments')->get();
440
        $activities->each(function (UserActivity $activity) use ($issue) {
441
            $activity->setRelation('issue', $issue);
442
        });
443
444
        return view('project.issue.partials.activities', [
445
            'noData'     => trans('tinyissue.no_comments'),
446
            'activities' => $activities,
447
            'project'    => $project,
448
            '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
    public function getIssueActivity(Project $project, Issue $issue)
461
    {
462
        $activities = $issue->generalActivities()->with('activity', 'user', 'assignTo')->get();
463
        $activities->each(function (UserActivity $activity) use ($issue) {
464
            $activity->setRelation('issue', $issue);
465
        });
466
467
        return view('project.issue.partials.activities', [
468
            'noData'     => trans('tinyissue.no_activities'),
469
            'activities' => $activities,
470
            'project'    => $project,
471
            'issue'      => $issue,
472
        ]);
473
    }
474
}
475