Passed
Pull Request — master (#6795)
by
unknown
08:23
created

CreateDropboxFileAction::buildLinks()   C

Complexity

Conditions 16
Paths 6

Size

Total Lines 36
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 16
eloc 24
c 1
b 0
f 0
nc 6
nop 4
dl 0
loc 36
rs 5.5666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Controller\Api;
8
9
use Chamilo\CoreBundle\Entity\ResourceLink;
10
use Chamilo\CoreBundle\Helpers\UserHelper;
11
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
12
use Chamilo\CoreBundle\Repository\SessionRepository;
13
use Chamilo\CourseBundle\Entity\CDropboxFile;
14
use Chamilo\CourseBundle\Entity\CDropboxPerson;
15
use Chamilo\CourseBundle\Entity\CDropboxPost;
16
use Chamilo\CourseBundle\Repository\CDropboxFileRepository;
17
use DateTime;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Symfony\Component\HttpFoundation\File\UploadedFile;
20
use Symfony\Component\HttpFoundation\JsonResponse;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpKernel\Attribute\AsController;
23
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
24
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
25
26
#[AsController]
27
final class CreateDropboxFileAction
28
{
29
    public function __invoke(
30
        Request $request,
31
        CDropboxFileRepository $repo,
32
        CourseRepository $courseRepo,
33
        SessionRepository $sessionRepo,
34
        EntityManagerInterface $em,
35
        UserHelper $userHelper
36
    ): JsonResponse {
37
        // --- Contexto
38
        $cid = (int) $request->query->get('cid', 0);
39
        $sid = (int) $request->query->get('sid', 0);
40
        $gid = (int) $request->query->get('gid', 0);
41
        if ($cid <= 0) {
42
            throw new BadRequestHttpException('Missing or invalid "cid".');
43
        }
44
        $user = $userHelper->getCurrent();
45
        if (!$user) {
46
            throw new UnauthorizedHttpException('', 'Unauthorized.');
47
        }
48
49
        // --- Normaliza: queremos SIEMPRE uploadFile
50
        /** @var UploadedFile|null $file */
51
        $file = $request->files->get('uploadFile');
52
        if (!$file) {
53
            foreach ($request->files as $val) {
54
                if ($val instanceof UploadedFile) {
55
                    $file = $val;
56
                    $request->files->set('uploadFile', $val);
57
                    break;
58
                }
59
            }
60
        }
61
        if (!$file) {
62
            throw new BadRequestHttpException('"uploadFile" is required');
63
        }
64
65
        // --- Nodo padre: si no viene, usamos el del curso
66
        $parentId = (int) $request->request->get('parentResourceNodeId', 0);
67
        if ($parentId === 0) {
68
            $course = $courseRepo->find($cid);
69
            $parentId = $course?->getResourceNode()?->getId() ?? 0;
70
            if ($parentId === 0) {
71
                throw new BadRequestHttpException('parentResourceNodeId (categoryId) is required');
72
            }
73
        }
74
75
        $description = (string) $request->request->get('description', '');
76
        $categoryId  = (int) $request->request->get('categoryId', 0);
77
        /** @var string[] $tokens */
78
        $tokens      = (array) ($request->request->all('recipients') ?? []);
79
80
        // --- Asegura filename único (UNIQUE en filename)
81
        $original  = $file->getClientOriginalName() ?: 'upload.bin';
82
        $candidate = $original;
83
        $i = 1;
84
        while ($repo->findOneBy(['filename' => $candidate])) {
85
            $pi   = pathinfo($original);
86
            $name = $pi['filename'] ?? 'file';
87
            $ext  = isset($pi['extension']) ? '.'.$pi['extension'] : '';
88
            $candidate = $name.'_'.$i.$ext;
89
            $i++;
90
        }
91
92
        // --- Construye el recurso tipo archivo (activa ResourceListener)
93
        $now = new DateTime();
94
        $e = new CDropboxFile();
95
        $e->setFiletype('file');               // importante
96
        $e->setParentResourceNode($parentId);  // importante
97
        $e->setUploadFile($file);              // importante
98
99
        $e->setCId($cid);
100
        $e->setSessionId($sid);
101
        $e->setUploaderId($user->getId());
102
        $e->setTitle($candidate);
103
        $e->setFilename($candidate);
104
        $e->setFilesize((int) ($file->getSize() ?: 0));
105
        $e->setDescription($description);
106
        $e->setAuthor((string) $user->getFullName());
107
        $e->setUploadDate($now);
108
        $e->setLastUploadDate($now);
109
        $e->setCatId($categoryId);
110
111
        // Links de visibilidad (ResourceLinkArray)
112
        $e->setResourceLinkArray($this->buildLinks($tokens, $cid, $sid, $gid));
113
114
        // --- Guarda recurso para tener iid
115
        $em->persist($e);
116
        $em->flush();
117
118
        // -------- Legacy: Persons + Posts ----------
119
        // Persona para uploader
120
        $up = new CDropboxPerson();
121
        $up->setCId($cid);
122
        $up->setUserId($user->getId());
123
        $up->setFileId($e->getIid());
124
        $em->persist($up);
125
126
        $destUserIds = $this->extractUserIdsFromTokens($tokens, $user->getId());
127
        if (!$destUserIds) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $destUserIds of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
128
            $destUserIds = [$user->getId()];
129
        }
130
131
        foreach ($destUserIds as $destUid) {
132
            $post = new CDropboxPost();
133
            $post->setCId($cid);
134
            $post->setSessionId($sid ?? 0);
135
            $post->setFileId($e->getIid());
136
            $post->setDestUserId($destUid);
137
            $post->setCatId($categoryId);
138
            $post->setFeedbackDate(new DateTime());
139
            $em->persist($post);
140
141
            if ($destUid !== $user->getId()) {
142
                $p = new CDropboxPerson();
143
                $p->setCId($cid);
144
                $p->setUserId($destUid);
145
                $p->setFileId($e->getIid());
146
                $em->persist($p);
147
            }
148
        }
149
150
        $em->flush();
151
152
        return new JsonResponse([
153
            'ok'         => true,
154
            'iid'        => (int) $e->getIid(),
155
            'title'      => $e->getTitle(),
156
            'filename'   => $e->getFilename(),
157
            'filesize'   => $e->getFilesize(),
158
            'categoryId' => $e->getCatId(),
159
            'message'    => 'File uploaded successfully',
160
        ], 201);
161
    }
162
163
    private function buildLinks(array $tokens, int $cid, int $sid, int $gid): array
164
    {
165
        $tokens = array_values(array_filter(array_map('strval', $tokens)));
166
167
        if (empty($tokens) || (count($tokens) === 1 && strtolower($tokens[0]) === 'self')) {
168
            return [[
169
                'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
170
                'cid' => $cid,
171
                'sid' => $sid ?: null,
172
                'gid' => $gid ?: null,
173
            ]];
174
        }
175
176
        $out = [];
177
        foreach ($tokens as $t) {
178
            if (preg_match('/^USER:(\d+)$/i', $t, $m)) {
179
                $out[] = [
180
                    'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
181
                    'cid' => $cid, 'sid' => $sid ?: null, 'uid' => (int) $m[1],
182
                ];
183
            } elseif (preg_match('/^GROUP:(\d+)$/i', $t, $m)) {
184
                $out[] = [
185
                    'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
186
                    'cid' => $cid, 'sid' => $sid ?: null, 'gid' => (int) $m[1],
187
                ];
188
            } elseif (preg_match('/^user_(\d+)$/i', $t, $m)) {
189
                $out[] = [
190
                    'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
191
                    'cid' => $cid, 'sid' => $sid ?: null, 'uid' => (int) $m[1],
192
                ];
193
            }
194
        }
195
196
        return $out ?: [[
197
            'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
198
            'cid' => $cid, 'sid' => $sid ?: null, 'gid' => $gid ?: null,
199
        ]];
200
    }
201
202
    private function extractUserIdsFromTokens(array $tokens, int $uploaderId): array
203
    {
204
        $ids = [];
205
        foreach ($tokens as $t) {
206
            $s = (string) $t;
207
            if (strtolower($s) === 'self') {
208
                $ids[] = $uploaderId;
209
            } elseif (preg_match('/^USER:(\d+)$/i', $s, $m)) {
210
                $ids[] = (int) $m[1];
211
            } elseif (preg_match('/^user_(\d+)$/i', $s, $m)) {
212
                $ids[] = (int) $m[1];
213
            }
214
        }
215
        return array_values(array_unique(array_filter($ids, fn($v) => (int)$v > 0)));
216
    }
217
}
218