Passed
Push — master ( d2ffdf...2a3437 )
by
unknown
17:22 queued 08:31
created

CreateDropboxFileAction::__invoke()   C

Complexity

Conditions 14
Paths 58

Size

Total Lines 119
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 79
c 1
b 0
f 0
nc 58
nop 6
dl 0
loc 119
rs 5.4715

How to fix   Long Method    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
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
        /** @var UploadedFile|null $file */
50
        $file = $request->files->get('uploadFile');
51
        if (!$file) {
52
            // Fallback: accept any uploaded file under a different key and remap it
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
        $parentId = (int) $request->request->get('parentResourceNodeId', 0);
66
        if ($parentId === 0) {
67
            $course = $courseRepo->find($cid);
68
            $parentId = $course?->getResourceNode()?->getId() ?? 0;
69
            if ($parentId === 0) {
70
                throw new BadRequestHttpException('parentResourceNodeId (categoryId) is required');
71
            }
72
        }
73
74
        $description = (string) $request->request->get('description', '');
75
        $categoryId  = (int) $request->request->get('categoryId', 0);
76
        /** @var string[] $tokens */
77
        $tokens      = (array) ($request->request->all('recipients') ?? []);
78
79
        // Ensure filename uniqueness
80
        $original  = $file->getClientOriginalName() ?: 'upload.bin';
81
        $candidate = $original;
82
        $i = 1;
83
        while ($repo->findOneBy(['filename' => $candidate])) {
84
            $pi   = pathinfo($original);
85
            $name = $pi['filename'] ?? 'file';
86
            $ext  = isset($pi['extension']) ? '.'.$pi['extension'] : '';
87
            $candidate = $name.'_'.$i.$ext;
88
            $i++;
89
        }
90
91
        $now = new DateTime();
92
        $e = new CDropboxFile();
93
        $e->setFiletype('file');
94
        $e->setParentResourceNode($parentId);
95
        $e->setUploadFile($file);
96
97
        $e->setCId($cid);
98
        $e->setSessionId($sid);
99
        $e->setUploaderId($user->getId());
100
        $e->setTitle($candidate);
101
        $e->setFilename($candidate);
102
        $e->setFilesize((int) ($file->getSize() ?: 0));
103
        $e->setDescription($description);
104
        $e->setAuthor((string) $user->getFullName());
105
        $e->setUploadDate($now);
106
        $e->setLastUploadDate($now);
107
        $e->setCatId($categoryId);
108
109
        // Link visibility (course/session/user/group)
110
        $e->setResourceLinkArray($this->buildLinks($tokens, $cid, $sid, $gid));
111
112
        $em->persist($e);
113
        $em->flush();
114
115
        // Extract real recipients; if none, leave it as a "Sent only" file (no recipients).
116
        $destUserIds = $this->extractUserIdsFromTokens($tokens);
117
118
        foreach ($destUserIds as $destUid) {
119
            // Create post (feedback/thread seed)
120
            $post = new CDropboxPost();
121
            $post->setCId($cid);
122
            $post->setSessionId($sid ?? 0);
123
            $post->setFileId($e->getIid());
124
            $post->setDestUserId($destUid);
125
            $post->setCatId($categoryId);
126
            $post->setFeedbackDate(new DateTime());
127
            $em->persist($post);
128
129
            // Create visibility for the recipient
130
            $p = new CDropboxPerson();
131
            $p->setCId($cid);
132
            $p->setUserId($destUid);
133
            $p->setFileId($e->getIid());
134
            $em->persist($p);
135
        }
136
137
        $em->flush();
138
139
        return new JsonResponse([
140
            'ok'         => true,
141
            'iid'        => (int) $e->getIid(),
142
            'title'      => $e->getTitle(),
143
            'filename'   => $e->getFilename(),
144
            'filesize'   => $e->getFilesize(),
145
            'categoryId' => $e->getCatId(),
146
            'message'    => 'File uploaded successfully',
147
        ], 201);
148
    }
149
150
    private function buildLinks(array $tokens, int $cid, int $sid, int $gid): array
151
    {
152
        $tokens = array_values(array_filter(array_map('strval', $tokens)));
153
154
        // If there are no tokens (or only "self"), keep it visible to the course/session/group context only.
155
        if (empty($tokens) || (count($tokens) === 1 && strtolower($tokens[0]) === 'self')) {
156
            return [[
157
                'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
158
                'cid' => $cid,
159
                'sid' => $sid ?: null,
160
                'gid' => $gid ?: null,
161
            ]];
162
        }
163
164
        $out = [];
165
        foreach ($tokens as $t) {
166
            if (preg_match('/^USER:(\d+)$/i', $t, $m)) {
167
                $out[] = [
168
                    'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
169
                    'cid' => $cid, 'sid' => $sid ?: null, 'uid' => (int) $m[1],
170
                ];
171
            } elseif (preg_match('/^GROUP:(\d+)$/i', $t, $m)) {
172
                $out[] = [
173
                    'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
174
                    'cid' => $cid, 'sid' => $sid ?: null, 'gid' => (int) $m[1],
175
                ];
176
            } elseif (preg_match('/^user_(\d+)$/i', $t, $m)) {
177
                $out[] = [
178
                    'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
179
                    'cid' => $cid, 'sid' => $sid ?: null, 'uid' => (int) $m[1],
180
                ];
181
            }
182
        }
183
184
        return $out ?: [[
185
            'visibility' => ResourceLink::VISIBILITY_PUBLISHED,
186
            'cid' => $cid, 'sid' => $sid ?: null, 'gid' => $gid ?: null,
187
        ]];
188
    }
189
190
    /**
191
     * Extract only real recipient user IDs from tokens.
192
     * The uploader must NOT be included here, even if "self" is present.
193
     *
194
     * @param array $tokens
195
     * @return int[]
196
     */
197
    private function extractUserIdsFromTokens(array $tokens): array
198
    {
199
        $ids = [];
200
        foreach ($tokens as $t) {
201
            $s = (string) $t;
202
            if (preg_match('/^USER:(\d+)$/i', $s, $m)) {
203
                $ids[] = (int) $m[1];
204
            } elseif (preg_match('/^user_(\d+)$/i', $s, $m)) {
205
                $ids[] = (int) $m[1];
206
            }
207
        }
208
        return array_values(array_unique(array_filter($ids, fn($v) => (int)$v > 0)));
209
    }
210
}
211