Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
24.07% |
26 / 108 |
|
33.33% |
5 / 15 |
CRAP | |
0.00% |
0 / 1 |
DocumentController | |
24.07% |
26 / 108 |
|
33.33% |
5 / 15 |
603.25 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
1 | |||
getDomain | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModel | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getModelClass | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getFormType | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getRouteName | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
getListData | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
indexAction | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
downloadAction | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
12 | |||
deleteConfirmationAction | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
42 | |||
listAction | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
gridAction | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
formPrePersistData | |
58.33% |
14 / 24 |
|
0.00% |
0 / 1 |
14.86 | |||
shareAction | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
favoriteAction | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * This file is part of the MADIS - RGPD Management application. |
5 | * |
6 | * @copyright Copyright (c) 2018-2019 Soluris - Solutions Numériques Territoriales Innovantes |
7 | * |
8 | * This program is free software: you can redistribute it and/or modify |
9 | * it under the terms of the GNU Affero General Public License as published by |
10 | * the Free Software Foundation, either version 3 of the License, or |
11 | * (at your option) any later version. |
12 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU Affero General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Affero General Public License |
19 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
20 | */ |
21 | |
22 | declare(strict_types=1); |
23 | |
24 | namespace App\Domain\Documentation\Controller; |
25 | |
26 | use App\Application\Controller\CRUDController; |
27 | use App\Application\Symfony\Security\UserProvider; |
28 | use App\Domain\Documentation\Form\Type\DocumentType; |
29 | use App\Domain\Documentation\Model; |
30 | use App\Domain\Documentation\Repository; |
31 | use App\Domain\User\Model\User; |
32 | use Doctrine\ORM\EntityManagerInterface; |
33 | use Gaufrette\Exception\FileNotFound; |
34 | use Gaufrette\FilesystemInterface; |
35 | use Knp\Snappy\Pdf; |
36 | use Ramsey\Uuid\Uuid; |
37 | use Symfony\Component\HttpFoundation\BinaryFileResponse; |
38 | use Symfony\Component\HttpFoundation\Request; |
39 | use Symfony\Component\HttpFoundation\RequestStack; |
40 | use Symfony\Component\HttpFoundation\Response; |
41 | use Symfony\Component\HttpFoundation\ResponseHeaderBag; |
42 | use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; |
43 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
44 | use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; |
45 | use Symfony\Contracts\Translation\TranslatorInterface; |
46 | |
47 | /** |
48 | * @property Repository\Document $repository |
49 | */ |
50 | class DocumentController extends CRUDController |
51 | { |
52 | /** |
53 | * @var AuthorizationCheckerInterface |
54 | */ |
55 | protected $authorizationChecker; |
56 | |
57 | /** |
58 | * @var UserProvider |
59 | */ |
60 | protected $userProvider; |
61 | |
62 | /** |
63 | * @var FilesystemInterface |
64 | */ |
65 | protected $documentFilesystem; |
66 | |
67 | /** |
68 | * @var FilesystemInterface |
69 | */ |
70 | protected $thumbFilesystem; |
71 | |
72 | /** |
73 | * @var RequestStack |
74 | */ |
75 | protected $requestStack; |
76 | |
77 | /** |
78 | * @var Repository\Category |
79 | */ |
80 | protected $categoryRepository; |
81 | |
82 | public function __construct( |
83 | EntityManagerInterface $entityManager, |
84 | TranslatorInterface $translator, |
85 | Repository\Document $repository, |
86 | Repository\Category $categoryRepository, |
87 | AuthorizationCheckerInterface $authorizationChecker, |
88 | UserProvider $userProvider, |
89 | FilesystemInterface $documentFilesystem, |
90 | FilesystemInterface $thumbFilesystem, |
91 | Pdf $pdf, |
92 | RequestStack $requestStack, |
93 | ) { |
94 | parent::__construct($entityManager, $translator, $repository, $pdf, $userProvider, $authorizationChecker); |
95 | $this->authorizationChecker = $authorizationChecker; |
96 | $this->documentFilesystem = $documentFilesystem; |
97 | $this->thumbFilesystem = $thumbFilesystem; |
98 | $this->requestStack = $requestStack; |
99 | $this->categoryRepository = $categoryRepository; |
100 | } |
101 | |
102 | protected function getDomain(): string |
103 | { |
104 | return 'documentation'; |
105 | } |
106 | |
107 | protected function getModel(): string |
108 | { |
109 | return 'document'; |
110 | } |
111 | |
112 | protected function getModelClass(): string |
113 | { |
114 | return Model\Document::class; |
115 | } |
116 | |
117 | protected function getFormType(): string |
118 | { |
119 | return DocumentType::class; |
120 | } |
121 | |
122 | protected function getRouteName(?string $template = null): string |
123 | { |
124 | if ('list' === $template) { |
125 | return "{$this->getDomain()}_{$this->getModel()}_index"; |
126 | } |
127 | |
128 | return "{$this->getDomain()}_{$this->getModel()}_{$template}"; |
129 | } |
130 | |
131 | protected function getListData() |
132 | { |
133 | $order = [ |
134 | 'pinned' => 'DESC', |
135 | 'createdAt' => 'DESC', |
136 | ]; |
137 | |
138 | // Everybody can access all documents |
139 | return $this->repository->findAll($order); |
140 | } |
141 | |
142 | public function indexAction() |
143 | { |
144 | /** |
145 | * @var User $user |
146 | */ |
147 | $user = $this->getUser(); |
148 | if ($user->isDocumentView()) { |
149 | return $this->gridAction(); |
150 | } |
151 | |
152 | return $this->listAction(); |
153 | } |
154 | |
155 | /** |
156 | * Trigger document file download. |
157 | * |
158 | * @return BinaryFileResponse |
159 | */ |
160 | public function downloadAction(string $name) |
161 | { |
162 | $doc = $this->repository->findOneByName($name); |
163 | |
164 | if (!$doc) { |
165 | $doc = $this->repository->findOneById($name); |
166 | } |
167 | |
168 | if (!$doc) { |
169 | throw new NotFoundHttpException('Document introuvable'); |
170 | } |
171 | |
172 | $fileStream = sprintf('gaufrette://documentation_document/%s', $doc->getFile()); |
173 | |
174 | $response = new BinaryFileResponse($fileStream); |
175 | $mimeType = $this->documentFilesystem->mimeType($doc->getFile()); |
176 | $ext = pathinfo($doc->getFile(), PATHINFO_EXTENSION); |
177 | $response->headers->set('Content-Type', $mimeType); |
178 | $response->setContentDisposition( |
179 | ResponseHeaderBag::DISPOSITION_ATTACHMENT, |
180 | $doc->getName() . '.' . $ext |
181 | ); |
182 | |
183 | return $response; |
184 | } |
185 | |
186 | public function deleteConfirmationAction(string $id): Response |
187 | { |
188 | /** @var Model\Document $doc */ |
189 | $doc = $this->repository->findOneByID($id); |
190 | if (!$doc) { |
191 | throw new NotFoundHttpException('Document introuvable'); |
192 | } |
193 | // check if user is creator or admin |
194 | if (!$this->authorizationChecker->isGranted('ROLE_ADMIN') && $this->userProvider->getAuthenticatedUser() !== $doc->getCreator()) { |
195 | throw new NotFoundHttpException('Document introuvable'); |
196 | } |
197 | |
198 | if ($doc->getFile()) { |
199 | try { |
200 | $this->documentFilesystem->delete($doc->getFile()); |
201 | } catch (FileNotFound $e) { |
202 | // File does not exist, do nothing |
203 | } |
204 | } |
205 | |
206 | return parent::deleteConfirmationAction($id); // TODO: Change the autogenerated stub |
207 | } |
208 | |
209 | /* |
210 | * The list action view |
211 | * Get data & display them. |
212 | */ |
213 | public function listAction(): Response |
214 | { |
215 | // Set default view to list for current user |
216 | /** |
217 | * @var User $user |
218 | */ |
219 | $user = $this->getUser(); |
220 | $user->setDocumentView(false); |
221 | $this->entityManager->flush(); |
222 | |
223 | $categories = $this->categoryRepository->findAll(['name' => 'ASC']); |
224 | |
225 | return $this->render($this->getTemplatingBasePath('list'), [ |
226 | 'objects' => $this->getListData(), |
227 | 'categories' => $categories, |
228 | ]); |
229 | } |
230 | |
231 | public function gridAction(): Response |
232 | { |
233 | // Set default view to list for current user |
234 | /** |
235 | * @var User $user |
236 | */ |
237 | $user = $this->getUser(); |
238 | $user->setDocumentView(true); |
239 | $this->entityManager->flush(); |
240 | |
241 | $categories = $this->categoryRepository->findAll(['name' => 'ASC']); |
242 | |
243 | return $this->render($this->getTemplatingBasePath('grid'), [ |
244 | 'objects' => $this->getListData(), |
245 | 'categories' => $categories, |
246 | ]); |
247 | } |
248 | |
249 | /** |
250 | * @param Model\Document $object |
251 | */ |
252 | public function formPrePersistData($object, $form = null) |
253 | { |
254 | if (!$object->getId() && !$this->authorizationChecker->isGranted('ROLE_ADMIN') && $this->userProvider->getAuthenticatedUser() !== $object->getCreator()) { |
255 | throw new NotFoundHttpException('Document introuvable'); |
256 | } |
257 | if (false === $object->getIsLink() && null !== $file = $object->getUploadedFile()) { |
258 | $filename = Uuid::uuid4()->toString() . '.' . $file->getClientOriginalExtension(); |
259 | |
260 | $this->documentFilesystem->write($filename, \fopen($file->getRealPath(), 'r')); |
261 | $size = $this->documentFilesystem->size($filename); |
262 | |
263 | $object->setSize($size); |
264 | |
265 | $object->setFile($filename); |
266 | $object->setUploadedFile(null); |
267 | |
268 | $url = $this->generateUrl('documentation_document_download', [ |
269 | 'name' => $filename, |
270 | ], UrlGeneratorInterface::NETWORK_PATH); |
271 | |
272 | $object->setUrl($url); |
273 | } elseif (true === $object->getIsLink()) { |
274 | $object->setFile(''); |
275 | $object->setSize(0); |
276 | } |
277 | if (null !== $thumb = $object->getThumbUploadedFile()) { |
278 | $filename = Uuid::uuid4()->toString() . '.' . $thumb->getClientOriginalExtension(); |
279 | $this->thumbFilesystem->write($filename, \fopen($thumb->getRealPath(), 'r')); |
280 | |
281 | $object->setThumbUploadedFile(null); |
282 | $object->setThumbUrl('/uploads/documentation/vignettes/' . $filename); |
283 | } |
284 | |
285 | if ($object->getRemoveThumb()) { |
286 | $object->setThumbUploadedFile(null); |
287 | $object->setThumbUrl(null); |
288 | } |
289 | } |
290 | |
291 | /** |
292 | * Trigger download or redirect to link when a user open a share link. |
293 | */ |
294 | public function shareAction(string $id) |
295 | { |
296 | $doc = $this->repository->findOneByID($id); |
297 | |
298 | if (!$doc) { |
299 | throw new NotFoundHttpException('Document introuvable'); |
300 | } |
301 | |
302 | if ($doc->getIsLink()) { |
303 | return $this->redirect($doc->getUrl()); |
304 | } |
305 | |
306 | return $this->downloadAction($doc->getFile()); |
307 | } |
308 | |
309 | /** |
310 | * Mark this document as favorite for the current user. |
311 | */ |
312 | public function favoriteAction(Request $request, string $id) |
313 | { |
314 | /** |
315 | * @var Model\Document |
316 | */ |
317 | $doc = $this->repository->findOneByID($id); |
318 | /** |
319 | * @var User |
320 | */ |
321 | $user = $this->getUser(); |
322 | if (!$doc) { |
323 | throw new NotFoundHttpException('Document introuvable'); |
324 | } |
325 | |
326 | $favorited = $user->getFavoriteDocuments(); |
327 | |
328 | // Is the current document already favorited ? |
329 | if ($favorited->contains($doc)) { |
330 | // If so, remove it |
331 | $favorited->removeElement($doc); |
332 | $doc->removeFavoritedUser($user); |
333 | } else { |
334 | // Other wise, add it |
335 | $favorited->add($doc); |
336 | $doc->addFavoritedUser($user); |
337 | } |
338 | |
339 | $user->setFavoriteDocuments($favorited); |
340 | |
341 | $this->entityManager->persist($user); |
342 | $this->entityManager->persist($doc); |
343 | $this->entityManager->flush(); |
344 | |
345 | $this->getDoctrine()->getManagerForClass(User::class)->flush(); |
346 | |
347 | return $this->redirect($request->get('back')); |
348 | } |
349 | } |