]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/AttachmentController.php
Updated API auth to allow public user if given permission
[bookstack] / app / Http / Controllers / AttachmentController.php
1 <?php namespace BookStack\Http\Controllers;
2
3 use BookStack\Entities\Repos\PageRepo;
4 use BookStack\Exceptions\FileUploadException;
5 use BookStack\Exceptions\NotFoundException;
6 use BookStack\Uploads\Attachment;
7 use BookStack\Uploads\AttachmentService;
8 use Exception;
9 use Illuminate\Contracts\Filesystem\FileNotFoundException;
10 use Illuminate\Http\Request;
11 use Illuminate\Validation\ValidationException;
12
13 class AttachmentController extends Controller
14 {
15     protected $attachmentService;
16     protected $attachment;
17     protected $pageRepo;
18
19     /**
20      * AttachmentController constructor.
21      */
22     public function __construct(AttachmentService $attachmentService, Attachment $attachment, PageRepo $pageRepo)
23     {
24         $this->attachmentService = $attachmentService;
25         $this->attachment = $attachment;
26         $this->pageRepo = $pageRepo;
27         parent::__construct();
28     }
29
30
31     /**
32      * Endpoint at which attachments are uploaded to.
33      * @throws ValidationException
34      * @throws NotFoundException
35      */
36     public function upload(Request $request)
37     {
38         $this->validate($request, [
39             'uploaded_to' => 'required|integer|exists:pages,id',
40             'file' => 'required|file'
41         ]);
42
43         $pageId = $request->get('uploaded_to');
44         $page = $this->pageRepo->getById($pageId);
45
46         $this->checkPermission('attachment-create-all');
47         $this->checkOwnablePermission('page-update', $page);
48
49         $uploadedFile = $request->file('file');
50
51         try {
52             $attachment = $this->attachmentService->saveNewUpload($uploadedFile, $pageId);
53         } catch (FileUploadException $e) {
54             return response($e->getMessage(), 500);
55         }
56
57         return response()->json($attachment);
58     }
59
60     /**
61      * Update an uploaded attachment.
62      * @throws ValidationException
63      * @throws NotFoundException
64      */
65     public function uploadUpdate(Request $request, $attachmentId)
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->pageRepo->getById($pageId);
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      * @throws ValidationException
97      * @throws NotFoundException
98      */
99     public function update(Request $request, $attachmentId)
100     {
101         $this->validate($request, [
102             'uploaded_to' => 'required|integer|exists:pages,id',
103             'name' => 'required|string|min:1|max:255',
104             'link' =>  'string|min:1|max:255'
105         ]);
106
107         $pageId = $request->get('uploaded_to');
108         $page = $this->pageRepo->getById($pageId);
109         $attachment = $this->attachment->findOrFail($attachmentId);
110
111         $this->checkOwnablePermission('page-update', $page);
112         $this->checkOwnablePermission('attachment-create', $attachment);
113
114         if (intval($pageId) !== intval($attachment->uploaded_to)) {
115             return $this->jsonError(trans('errors.attachment_page_mismatch'));
116         }
117
118         $attachment = $this->attachmentService->updateFile($attachment, $request->all());
119         return response()->json($attachment);
120     }
121
122     /**
123      * Attach a link to a page.
124      * @throws ValidationException
125      * @throws NotFoundException
126      */
127     public function attachLink(Request $request)
128     {
129         $this->validate($request, [
130             'uploaded_to' => 'required|integer|exists:pages,id',
131             'name' => 'required|string|min:1|max:255',
132             'link' =>  'required|string|min:1|max:255'
133         ]);
134
135         $pageId = $request->get('uploaded_to');
136         $page = $this->pageRepo->getById($pageId);
137
138         $this->checkPermission('attachment-create-all');
139         $this->checkOwnablePermission('page-update', $page);
140
141         $attachmentName = $request->get('name');
142         $link = $request->get('link');
143         $attachment = $this->attachmentService->saveNewFromLink($attachmentName, $link, $pageId);
144
145         return response()->json($attachment);
146     }
147
148     /**
149      * Get the attachments for a specific page.
150      */
151     public function listForPage(int $pageId)
152     {
153         $page = $this->pageRepo->getById($pageId);
154         $this->checkOwnablePermission('page-view', $page);
155         return response()->json($page->attachments);
156     }
157
158     /**
159      * Update the attachment sorting.
160      * @throws ValidationException
161      * @throws NotFoundException
162      */
163     public function sortForPage(Request $request, int $pageId)
164     {
165         $this->validate($request, [
166             'files' => 'required|array',
167             'files.*.id' => 'required|integer',
168         ]);
169         $page = $this->pageRepo->getById($pageId);
170         $this->checkOwnablePermission('page-update', $page);
171
172         $attachments = $request->get('files');
173         $this->attachmentService->updateFileOrderWithinPage($attachments, $pageId);
174         return response()->json(['message' => trans('entities.attachments_order_updated')]);
175     }
176
177     /**
178      * Get an attachment from storage.
179      * @throws FileNotFoundException
180      * @throws NotFoundException
181      */
182     public function get(int $attachmentId)
183     {
184         $attachment = $this->attachment->findOrFail($attachmentId);
185         try {
186             $page = $this->pageRepo->getById($attachment->uploaded_to);
187         } catch (NotFoundException $exception) {
188             throw new NotFoundException(trans('errors.attachment_not_found'));
189         }
190
191         $this->checkOwnablePermission('page-view', $page);
192
193         if ($attachment->external) {
194             return redirect($attachment->path);
195         }
196
197         $attachmentContents = $this->attachmentService->getAttachmentFromStorage($attachment);
198         return $this->downloadResponse($attachmentContents, $attachment->getFileName());
199     }
200
201     /**
202      * Delete a specific attachment in the system.
203      * @param $attachmentId
204      * @return mixed
205      * @throws Exception
206      */
207     public function delete(int $attachmentId)
208     {
209         $attachment = $this->attachment->findOrFail($attachmentId);
210         $this->checkOwnablePermission('attachment-delete', $attachment);
211         $this->attachmentService->deleteFile($attachment);
212         return response()->json(['message' => trans('entities.attachments_deleted')]);
213     }
214 }