EntryController::uploadFormAction()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 35
Code Lines 23

Duplication

Lines 5
Ratio 14.29 %

Importance

Changes 0
Metric Value
dl 5
loc 35
rs 8.439
c 0
b 0
f 0
cc 6
eloc 23
nc 6
nop 2
1
<?php
2
/*
3
  ÁTICA - Aplicación web para la gestión documental de centros educativos
4
5
  Copyright (C) 2015-2017: Luis Ramón López López
6
7
  This program is free software: you can redistribute it and/or modify
8
  it under the terms of the GNU Affero General Public License as published by
9
  the Free Software Foundation, either version 3 of the License, or
10
  (at your option) any later version.
11
12
  This program is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
  GNU Affero General Public License for more details.
16
17
  You should have received a copy of the GNU Affero General Public License
18
  along with this program.  If not, see [http://www.gnu.org/licenses/].
19
*/
20
21
namespace AppBundle\Controller\Documentation;
22
23
use AppBundle\Entity\Documentation\DownloadLog;
24
use AppBundle\Entity\Documentation\Entry;
25
use AppBundle\Entity\Documentation\Folder;
26
use AppBundle\Entity\Documentation\FolderPermission;
27
use AppBundle\Entity\Documentation\History;
28
use AppBundle\Entity\User;
29
use AppBundle\Entity\Documentation\Version;
30
use AppBundle\Form\Model\DocumentUpload;
31
use AppBundle\Form\Type\Documentation\EntryType;
32
use AppBundle\Form\Type\Documentation\UploadType;
33
use AppBundle\Security\EntryVoter;
34
use AppBundle\Security\FolderVoter;
35
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
36
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
37
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
38
use Symfony\Component\Config\Definition\Exception\Exception;
39
use Symfony\Component\HttpFoundation\BinaryFileResponse;
40
use Symfony\Component\HttpFoundation\File\UploadedFile;
41
use Symfony\Component\HttpFoundation\Request;
42
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
43
44
class EntryController extends Controller
45
{
46
    /**
47
     * @Route("/publico/{id}/{publicToken}", name="documentation_entry_public_download", requirements={"id" = "\d+"}, methods={"GET"})
48
     * @Security("entry.isPublic()")
49
     */
50
    public function publicDownloadEntryAction(Request $request, Entry $entry)
51
    {
52
        return $this->doDownloadEntry($request, $entry, null);
53
    }
54
55
    /**
56
     * @Route("/documentos/descargar/{id}", name="documentation_entry_download", requirements={"id" = "\d+"}, methods={"GET"})
57
     * @Security("is_granted('ENTRY_ACCESS', entry)")
58
     */
59
    public function downloadEntryAction(Request $request, Entry $entry)
60
    {
61
        return $this->doDownloadEntry($request, $entry, $this->getUser());
62
    }
63
64
    /**
65
     * @param Request $request
66
     * @param Entry $entry
67
     * @param User|null $user
68
     *
69
     * @return BinaryFileResponse
70
     */
71
    private function doDownloadEntry(Request $request, Entry $entry, User $user = null)
72
    {
73
        $version = $entry->getCurrentVersion();
74
        if (null === $version || null === $version->getFile()) {
75
            throw $this->createNotFoundException();
76
        }
77
        return $this->doDownloadVersion($request, $version, $user);
78
    }
79
80
    /**
81
     * @param Request $request
82
     * @param Version $version
83
     * @param User|null $user
84
     *
85
     * @return BinaryFileResponse
86
     */
87
    private function doDownloadVersion(Request $request, Version $version, User $user = null)
88
    {
89
        $filepath = 'gaufrette://entries/'.$version->getFile();
90
91
        $response = new BinaryFileResponse($filepath);
92
93
        $fileName = $version->getFileExtension() ? $version->getEntry()->getName().'.'.$version->getFileExtension() : $version->getEntry()->getName();
94
95
        $response
96
            ->setContentDisposition(
97
                ResponseHeaderBag::DISPOSITION_INLINE,
98
                $fileName
99
            );
100
101
        $em = $this->getDoctrine()->getManager();
102
103
        $log = new DownloadLog();
104
        $log
105
            ->setUser($user)
106
            ->setVersion($version->getVersionNr())
107
            ->setEntry($version->getEntry())
108
            ->setIpAddress($request->getClientIp());
109
110
        $em->persist($log);
111
112
        $em->flush();
113
114
        return $response;
115
    }
116
117
118
    /**
119
     * @Route("/carpeta/{id}/subir", name="documentation_folder_upload", methods={"GET", "POST"})
120
     * @Security("is_granted('FOLDER_UPLOAD', folder) and folder.getType() != constant('AppBundle\\Entity\\Documentation\\Folder::TYPE_TASKS')")
121
     */
122
    public function uploadFormAction(Request $request, Folder $folder)
123
    {
124
        $breadcrumb = FolderController::generateBreadcrumb($folder, false);
125
126
        $title = $this->get('translator')->trans('title.entry.new', [], 'documentation');
127
        $breadcrumb[] = ['fixed' => $title];
128
129
        $upload = new DocumentUpload();
130
131 View Code Duplication
        if ($this->isGranted(FolderVoter::MANAGE, $folder)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
            $profiles = $this->getDoctrine()->getManager()->getRepository('AppBundle:Element')->findAllProfilesByFolderPermission($folder, FolderPermission::PERMISSION_UPLOAD, true);
133
        } else {
134
            $profiles = $this->getDoctrine()->getManager()->getRepository('AppBundle:Element')->findAllProfilesByFolderPermissionAndUser($folder, FolderPermission::PERMISSION_UPLOAD, $this->getUser(), true);
135
        }
136
        $form = $this->createForm(UploadType::class, $upload, ['upload_profiles' => $profiles]);
137
138
        $form->handleRequest($request);
139
140
        if ($form->isSubmitted() && $form->isValid()) {
141
            $state = $this->getUploadStatus($request, $folder);
142
            if (null !== $state && $this->processFileUpload($folder, $upload, $state, $state)) {
143
                $this->addFlash('success', $this->get('translator')->trans('message.upload.save_ok', [], 'upload'));
144
                return $this->redirectToRoute('documentation', ['id' => $folder->getId()]);
145
            }
146
            $this->addFlash('error', $this->get('translator')->trans('message.upload.save_error', [], 'upload'));
147
        }
148
149
        return $this->render('documentation/folder_upload.html.twig', [
150
            'menu_path' => 'documentation',
151
            'title' => $title,
152
            'breadcrumb' => $breadcrumb,
153
            'folder' => $folder,
154
            'form' => $form->createView()
155
        ]);
156
    }
157
158
    /**
159
     * @param Folder $folder
160
     * @param DocumentUpload $upload
161
     * @param integer $versionState
162
     * @param integer $entryState
163
     */
164
    private function processFileUpload(Folder $folder, DocumentUpload $upload, $versionState = Version::STATUS_APPROVED, $entryState = Entry::STATUS_APPROVED)
165
    {
166
        $em = $this->getDoctrine()->getManager();
167
        $processedFileName = null;
168
        $filesystem = $this->get('entries_filesystem');
169
        try {
170
            /** @var UploadedFile $file */
171
            $file = $upload->getFile();
172
            $fileName = hash_file('sha256', $file->getRealPath());
173
            $fileName = substr($fileName, 0, 2).'/'.substr($fileName, 2, 2).'/'.$fileName;
174
            if (!$filesystem->has($fileName)) {
175
                $filesystem->write($fileName, file_get_contents($file->getRealPath()));
176
            }
177
            $processedFileName = $fileName;
178
179
            $name = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
180
            $entry = new Entry();
181
            $entry
182
                ->setName($upload->getTitle() ?: $name)
183
                ->setFolder($folder)
184
                ->setState($entryState)
185
                ->setElement($upload->getUploadProfile())
186
                ->setDescription($upload->getDescription());
187
188
            if ($upload->getCreateDate()) {
189
                $entry->setCreatedAt($upload->getCreateDate());
190
            }
191
192
            $em->persist($entry);
193
194
            $version = new Version();
195
            $version
196
                ->setEntry($entry)
197
                ->setFile($fileName)
198
                ->setFileExtension($file->getClientOriginalExtension())
199
                ->setFileMimeType($file->getMimeType())
200
                ->setState($versionState)
201
                ->setVersionNr($upload->getVersion());
202
203
            $entry->setCurrentVersion($version);
204
205
            $em->persist($version);
206
207
            $history = new History();
208
            $history
209
                ->setEntry($entry)
210
                ->setVersion($upload->getVersion())
211
                ->setCreatedBy($this->getUser())
212
                ->setEvent(History::LOG_CREATE);
213
214
            $em->persist($history);
215
216
            $em->flush();
217
218
            return true;
219
        } catch (\Exception $e) {
220
            // seguir la ejecución si ha ocurrido una excepción por el camino
221
        }
222
223
        if (null !== $processedFileName) {
224
            // ha ocurrido un error pero el fichero se había almacenado, borrarlo si no se estaba usando
225
            if (0 == (int) $em->getRepository('AppBundle:Documentation\Version')->countByFile($processedFileName)) {
226
                $filesystem->delete($processedFileName);
227
            }
228
        }
229
230
        return false;
231
    }
232
233
    /**
234
     * @param Request $request
235
     * @param Folder $folder
236
     * @return int|null
237
     */
238
    private function getUploadStatus(Request $request, Folder $folder)
239
    {
240
        $state = null;
241
        switch ($folder->getType()) {
242
            case Folder::TYPE_NORMAL:
243
                $state = Version::STATUS_APPROVED;
244
                break;
245
            case Folder::TYPE_WORKFLOW:
246
                $state = ($request->request->has('approve') && $this->isGranted(FolderVoter::APPROVE, $folder)) ? Version::STATUS_APPROVED : Version::STATUS_DRAFT;
247
        }
248
        return $state;
249
    }
250
251
    /**
252
     * @Route("/documentos/detalle/{id}", name="documentation_entry_detail", requirements={"id" = "\d+"}, methods={"GET", "POST"})
253
     * @Security("is_granted('ENTRY_ACCESS', entry)")
254
     */
255
    public function detailEntryAction(Request $request, Entry $entry)
256
    {
257
        $breadcrumb = FolderController::generateBreadcrumb($entry->getFolder(), false);
258
259
        $title = $this->get('translator')->trans('title.entry.edit', [], 'documentation');
260
        $breadcrumb[] = ['fixed' => $entry->getName()];
261
262
        $folder = $entry->getFolder();
263
        $isManager = $this->isGranted(FolderVoter::MANAGE, $folder);
264 View Code Duplication
        if ($isManager) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
265
            $profiles = $this->getDoctrine()->getManager()->getRepository('AppBundle:Element')->findAllProfilesByFolderPermission($folder, FolderPermission::PERMISSION_UPLOAD, true);
0 ignored issues
show
Bug introduced by
The method findAllProfilesByFolderPermission() does not exist on Doctrine\Common\Persistence\ObjectRepository. Did you maybe mean findAll()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
266
        } else {
267
            $profiles = $this->getDoctrine()->getManager()->getRepository('AppBundle:Element')->findAllProfilesByFolderPermissionAndUser($folder, FolderPermission::PERMISSION_UPLOAD, $this->getUser(), true);
0 ignored issues
show
Bug introduced by
The method findAllProfilesByFolderPermissionAndUser() does not exist on Doctrine\Common\Persistence\ObjectRepository. Did you maybe mean findAll()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
268
        }
269
270
        $isOwner = $this->isGranted(EntryVoter::MANAGE, $entry);
271
        $form = $this->createForm(EntryType::class, $entry, [
272
            'upload_profiles' => $profiles,
273
            'is_manager' => $isManager,
274
            'is_owner' => $isOwner,
275
            'name_locked' => $folder->getType() === Folder::TYPE_TASKS
276
        ]);
277
278
        $form->handleRequest($request);
279
280
        if ($form->isSubmitted() && $form->isValid()) {
281
            try {
282
                $this->getDoctrine()->getManager()->flush();
283
                $this->addFlash('success', $this->get('translator')->trans('message.entry.saved', [], 'documentation'));
284
                return $this->redirectToRoute('documentation', ['id' => $folder->getId()]);
285
            }
286
            catch(Exception $e) {
287
                $this->addFlash('error', $this->get('translator')->trans('message.entry.save_error', [], 'documentation'));
288
            }
289
        }
290
291
        return $this->render('documentation/entry_detail.html.twig', [
292
            'menu_path' => 'documentation',
293
            'title' => $title,
294
            'breadcrumb' => $breadcrumb,
295
            'permissions' => [
296
                'is_owner' => $isOwner,
297
                'is_manager' => $isManager,
298
                'is_reviewer' => $this->isGranted(FolderVoter::REVIEW, $folder),
299
                'is_approver' => $this->isGranted(FolderVoter::APPROVE, $folder)
300
            ],
301
            'entry' => $entry,
302
            'form' => $form->createView()
303
        ]);
304
    }
305
}
306