]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/AttachmentController.php
Updated issue template and added TinyMCE autolinking
[bookstack] / app / Http / Controllers / AttachmentController.php
1 <?php namespace BookStack\Http\Controllers;
2
3 use BookStack\Exceptions\FileUploadException;
4 use BookStack\Attachment;
5 use BookStack\Repos\EntityRepo;
6 use BookStack\Services\AttachmentService;
7 use Illuminate\Http\Request;
8
9 class AttachmentController extends Controller
10 {
11     protected $attachmentService;
12     protected $attachment;
13     protected $entityRepo;
14
15     /**
16      * AttachmentController constructor.
17      * @param AttachmentService $attachmentService
18      * @param Attachment $attachment
19      * @param EntityRepo $entityRepo
20      */
21     public function __construct(AttachmentService $attachmentService, Attachment $attachment, EntityRepo $entityRepo)
22     {
23         $this->attachmentService = $attachmentService;
24         $this->attachment = $attachment;
25         $this->entityRepo = $entityRepo;
26         parent::__construct();
27     }
28
29
30     /**
31      * Endpoint at which attachments are uploaded to.
32      * @param Request $request
33      * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\Response
34      */
35     public function upload(Request $request)
36     {
37         $this->validate($request, [
38             'uploaded_to' => 'required|integer|exists:pages,id',
39             'file' => 'required|file'
40         ]);
41
42         $pageId = $request->get('uploaded_to');
43         $page = $this->entityRepo->getById('page', $pageId, true);
44
45         $this->checkPermission('attachment-create-all');
46         $this->checkOwnablePermission('page-update', $page);
47
48         $uploadedFile = $request->file('file');
49
50         try {
51             $attachment = $this->attachmentService->saveNewUpload($uploadedFile, $pageId);
52         } catch (FileUploadException $e) {
53             return response($e->getMessage(), 500);
54         }
55
56         return response()->json($attachment);
57     }
58
59     /**
60      * Update an uploaded attachment.
61      * @param int $attachmentId
62      * @param Request $request
63      * @return mixed
64      */
65     public function uploadUpdate($attachmentId, Request $request)
66     {
67         $this->validate($request, [
68             'uploaded_to' => 'required|integer|exists:pages,id',
69             'file' => 'required|file'
70         ]);
71
72         $pageId = $request->get('uploaded_to');
73         $page = $this->entityRepo->getById('page', $pageId, true);
74         $attachment = $this->attachment->findOrFail($attachmentId);
75
76         $this->checkOwnablePermission('page-update', $page);
77         $this->checkOwnablePermission('attachment-create', $attachment);
78         
79         if (intval($pageId) !== intval($attachment->uploaded_to)) {
80             return $this->jsonError(trans('errors.attachment_page_mismatch'));
81         }
82
83         $uploadedFile = $request->file('file');
84
85         try {
86             $attachment = $this->attachmentService->saveUpdatedUpload($uploadedFile, $attachment);
87         } catch (FileUploadException $e) {
88             return response($e->getMessage(), 500);
89         }
90
91         return response()->json($attachment);
92     }
93
94     /**
95      * Update the details of an existing file.
96      * @param $attachmentId
97      * @param Request $request
98      * @return Attachment|mixed
99      */
100     public function update($attachmentId, Request $request)
101     {
102         $this->validate($request, [
103             'uploaded_to' => 'required|integer|exists:pages,id',
104             'name' => 'required|string|min:1|max:255',
105             'link' =>  'url|min:1|max:255'
106         ]);
107
108         $pageId = $request->get('uploaded_to');
109         $page = $this->entityRepo->getById('page', $pageId, true);
110         $attachment = $this->attachment->findOrFail($attachmentId);
111
112         $this->checkOwnablePermission('page-update', $page);
113         $this->checkOwnablePermission('attachment-create', $attachment);
114
115         if (intval($pageId) !== intval($attachment->uploaded_to)) {
116             return $this->jsonError(trans('errors.attachment_page_mismatch'));
117         }
118
119         $attachment = $this->attachmentService->updateFile($attachment, $request->all());
120         return response()->json($attachment);
121     }
122
123     /**
124      * Attach a link to a page.
125      * @param Request $request
126      * @return mixed
127      */
128     public function attachLink(Request $request)
129     {
130         $this->validate($request, [
131             'uploaded_to' => 'required|integer|exists:pages,id',
132             'name' => 'required|string|min:1|max:255',
133             'link' =>  'required|url|min:1|max:255'
134         ]);
135
136         $pageId = $request->get('uploaded_to');
137         $page = $this->entityRepo->getById('page', $pageId, true);
138
139         $this->checkPermission('attachment-create-all');
140         $this->checkOwnablePermission('page-update', $page);
141
142         $attachmentName = $request->get('name');
143         $link = $request->get('link');
144         $attachment = $this->attachmentService->saveNewFromLink($attachmentName, $link, $pageId);
145
146         return response()->json($attachment);
147     }
148
149     /**
150      * Get the attachments for a specific page.
151      * @param $pageId
152      * @return mixed
153      */
154     public function listForPage($pageId)
155     {
156         $page = $this->entityRepo->getById('page', $pageId, true);
157         $this->checkOwnablePermission('page-view', $page);
158         return response()->json($page->attachments);
159     }
160
161     /**
162      * Update the attachment sorting.
163      * @param $pageId
164      * @param Request $request
165      * @return mixed
166      */
167     public function sortForPage($pageId, Request $request)
168     {
169         $this->validate($request, [
170             'files' => 'required|array',
171             'files.*.id' => 'required|integer',
172         ]);
173         $page = $this->entityRepo->getById('page', $pageId);
174         $this->checkOwnablePermission('page-update', $page);
175
176         $attachments = $request->get('files');
177         $this->attachmentService->updateFileOrderWithinPage($attachments, $pageId);
178         return response()->json(['message' => trans('entities.attachments_order_updated')]);
179     }
180
181     /**
182      * Get an attachment from storage.
183      * @param $attachmentId
184      * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|\Symfony\Component\HttpFoundation\Response
185      */
186     public function get($attachmentId)
187     {
188         $attachment = $this->attachment->findOrFail($attachmentId);
189         $page = $this->entityRepo->getById('page', $attachment->uploaded_to);
190         $this->checkOwnablePermission('page-view', $page);
191
192         if ($attachment->external) {
193             return redirect($attachment->path);
194         }
195
196         $attachmentContents = $this->attachmentService->getAttachmentFromStorage($attachment);
197         return response($attachmentContents, 200, [
198             'Content-Type' => 'application/octet-stream',
199             'Content-Disposition' => 'attachment; filename="'. $attachment->getFileName() .'"'
200         ]);
201     }
202
203     /**
204      * Delete a specific attachment in the system.
205      * @param $attachmentId
206      * @return mixed
207      */
208     public function delete($attachmentId)
209     {
210         $attachment = $this->attachment->findOrFail($attachmentId);
211         $this->checkOwnablePermission('attachment-delete', $attachment);
212         $this->attachmentService->deleteFile($attachment);
213         return response()->json(['message' => trans('entities.attachments_deleted')]);
214     }
215 }