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