Passed
Push — master ( 0d7705...62fa37 )
by Yannick
09:28
created

AdminController::runCleanupTempUploads()   B

Complexity

Conditions 9
Paths 13

Size

Total Lines 57
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 34
c 0
b 0
f 0
nc 13
nop 2
dl 0
loc 57
rs 8.0555

How to fix   Long Method   

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\Admin;
8
9
use Chamilo\CoreBundle\Component\Composer\ScriptHandler;
10
use Chamilo\CoreBundle\Controller\BaseController;
11
use Chamilo\CoreBundle\Entity\ResourceLink;
12
use Chamilo\CoreBundle\Entity\ResourceType;
13
use Chamilo\CoreBundle\Helpers\AccessUrlHelper;
14
use Chamilo\CoreBundle\Helpers\QueryCacheHelper;
15
use Chamilo\CoreBundle\Helpers\TempUploadHelper;
16
use Chamilo\CoreBundle\Repository\Node\UserRepository;
17
use Chamilo\CoreBundle\Repository\ResourceFileRepository;
18
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
19
use Chamilo\CoreBundle\Settings\SettingsManager;
20
use Doctrine\ORM\EntityManagerInterface;
21
use Symfony\Component\HttpFoundation\JsonResponse;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Response;
24
use Symfony\Component\Routing\Annotation\Route;
25
use Symfony\Component\Security\Http\Attribute\IsGranted;
26
27
#[Route('/admin')]
28
class AdminController extends BaseController
29
{
30
    private const ITEMS_PER_PAGE = 50;
31
32
    public function __construct(
33
        private readonly ResourceNodeRepository $resourceNodeRepository,
34
        private readonly AccessUrlHelper $accessUrlHelper
35
    ) {}
36
37
    #[IsGranted('ROLE_ADMIN')]
38
    #[Route('/register-campus', name: 'admin_register_campus', methods: ['POST'])]
39
    public function registerCampus(Request $request, SettingsManager $settingsManager): Response
40
    {
41
        $requestData = $request->toArray();
42
        $doNotListCampus = (bool) $requestData['donotlistcampus'];
43
44
        $settingsManager->setUrl($this->accessUrlHelper->getCurrent());
45
        $settingsManager->updateSetting('platform.registered', 'true');
46
47
        $settingsManager->updateSetting(
48
            'platform.donotlistcampus',
49
            $doNotListCampus ? 'true' : 'false'
50
        );
51
52
        return new Response('', Response::HTTP_NO_CONTENT);
53
    }
54
55
    #[IsGranted('ROLE_ADMIN')]
56
    #[Route('/files_info', name: 'admin_files_info', methods: ['GET'])]
57
    public function listFilesInfo(Request $request, ResourceFileRepository $resourceFileRepository): Response
58
    {
59
        $page = $request->query->getInt('page', 1);
60
        $search = $request->query->get('search', '');
61
        $offset = ($page - 1) * self::ITEMS_PER_PAGE;
62
63
        $files = $resourceFileRepository->searchFiles($search, $offset, self::ITEMS_PER_PAGE);
64
        $totalItems = $resourceFileRepository->countFiles($search);
65
        $totalPages = $totalItems > 0 ? ceil($totalItems / self::ITEMS_PER_PAGE) : 1;
66
67
        $fileUrls = [];
68
        $filePaths = [];
69
        foreach ($files as $file) {
70
            $resourceNode = $file->getResourceNode();
71
            if ($resourceNode) {
72
                $fileUrls[$file->getId()] = $this->resourceNodeRepository->getResourceFileUrl($resourceNode);
73
                $creator = $resourceNode->getCreator();
74
            } else {
75
                $fileUrls[$file->getId()] = null;
76
                $creator = null;
77
            }
78
            $filePaths[$file->getId()] = '/upload/resource'.$this->resourceNodeRepository->getFilename($file);
79
        }
80
81
        return $this->render('@ChamiloCore/Admin/files_info.html.twig', [
82
            'files' => $files,
83
            'fileUrls' => $fileUrls,
84
            'filePaths' => $filePaths,
85
            'totalPages' => $totalPages,
86
            'currentPage' => $page,
87
            'search' => $search,
88
        ]);
89
    }
90
91
    #[IsGranted('ROLE_ADMIN')]
92
    #[Route('/resources_info', name: 'admin_resources_info', methods: ['GET'])]
93
    public function listResourcesInfo(Request $request, ResourceNodeRepository $resourceNodeRepo, EntityManagerInterface $em): Response
94
    {
95
        $resourceTypeId = $request->query->getInt('type');
96
        $resourceTypes = $em->getRepository(ResourceType::class)->findAll();
97
98
        $courses = [];
99
        if ($resourceTypeId > 0) {
100
            $resourceLinks = $em->getRepository(ResourceLink::class)->createQueryBuilder('rl')
101
                ->join('rl.resourceNode', 'rn')
102
                ->where('rn.resourceType = :type')
103
                ->setParameter('type', $resourceTypeId)
104
                ->getQuery()
105
                ->getResult()
106
            ;
107
108
            $seen = [];
109
            foreach ($resourceLinks as $link) {
110
                $course = $link->getCourse();
111
                $session = $link->getSession();
112
                $node = $link->getResourceNode();
113
114
                if (!$course) {
115
                    continue;
116
                }
117
118
                $key = $session
119
                    ? 's'.$session->getId().'-'.$course->getId()
120
                    : 'c'.$course->getId();
121
122
                if (!isset($seen[$key])) {
123
                    $seen[$key] = [
124
                        'type' => $session ? 'session' : 'course',
125
                        'id' => $session ? $session->getId() : $course->getId(),
126
                        'title' => $session ? $session->getTitle().' - '.$course->getTitle() : $course->getTitle(),
127
                        'url' => $session
128
                            ? '/course/'.$course->getId().'/home?sid='.$session->getId()
129
                            : '/course/'.$course->getId().'/home',
130
                        'count' => 0,
131
                        'items' => [],
132
                        'firstCreatedAt' => $node->getCreatedAt(),
133
                    ];
134
                }
135
136
                $seen[$key]['count']++;
137
                $seen[$key]['items'][] = $node->getTitle();
138
139
                if ($node->getCreatedAt() < $seen[$key]['firstCreatedAt']) {
140
                    $seen[$key]['firstCreatedAt'] = $node->getCreatedAt();
141
                }
142
            }
143
144
            $courses = array_values($seen);
145
            usort($courses, fn ($a, $b) => strnatcasecmp($a['title'], $b['title']));
146
        }
147
148
        return $this->render('@ChamiloCore/Admin/resources_info.html.twig', [
149
            'resourceTypes' => $resourceTypes,
150
            'selectedType' => $resourceTypeId,
151
            'courses' => $courses,
152
        ]);
153
    }
154
155
    #[IsGranted('ROLE_ADMIN')]
156
    #[Route('/test-cache-all-users', name: 'chamilo_core_user_test_cache_all_users')]
157
    public function testCacheAllUsers(UserRepository $userRepository): JsonResponse
158
    {
159
        // Without cache
160
        $startNoCache = microtime(true);
161
        $usersNoCache = $userRepository->findAllUsers(false);
162
        $timeNoCache = microtime(true) - $startNoCache;
163
164
        // With cache
165
        $startCache = microtime(true);
166
        $resultCached = $userRepository->findAllUsers(true);
167
        $timeCache = microtime(true) - $startCache;
168
169
        // Check if we have a key (we do if cache was used)
170
        $usersCache = $resultCached['data'] ?? $resultCached;
171
172
        $cacheKey = $resultCached['cache_key'] ?? null;
173
174
        return $this->json([
175
            'without_cache' => [
176
                'count' => \count($usersNoCache),
177
                'execution_time' => $timeNoCache,
178
            ],
179
            'with_cache' => [
180
                'count' => \count($usersCache),
181
                'execution_time' => $timeCache,
182
                'cache_key' => $cacheKey,
183
            ],
184
        ]);
185
    }
186
187
    #[IsGranted('ROLE_ADMIN')]
188
    #[Route(path: '/test-cache-all-users/invalidate', name: 'chamilo_core_user_test_cache_all_users_invalidate')]
189
    public function invalidateCacheAllUsers(QueryCacheHelper $queryCacheHelper): JsonResponse
190
    {
191
        $cacheKey = $queryCacheHelper->getCacheKey('findAllUsers', []);
192
        $queryCacheHelper->invalidate('findAllUsers');
193
194
        return $this->json([
195
            'message' => 'Cache for users invalidated!',
196
            'invalidated_cache_key' => $cacheKey,
197
        ]);
198
    }
199
200
    #[IsGranted('ROLE_ADMIN')]
201
    #[Route('/cleanup-temp-uploads', name: 'admin_cleanup_temp_uploads', methods: ['GET'])]
202
    public function showCleanupTempUploads(
203
        TempUploadHelper $tempUploadHelper,
204
    ): Response {
205
        $stats = $tempUploadHelper->stats(); // ['files' => int, 'bytes' => int]
206
207
        return $this->render('@ChamiloCore/Admin/cleanup_temp_uploads.html.twig', [
208
            'tempDir' => $tempUploadHelper->getTempDir(),
209
            'stats' => $stats,
210
            'defaultOlderThan' => 0, // 0 = delete all
211
        ]);
212
    }
213
214
    #[IsGranted('ROLE_ADMIN')]
215
    #[Route('/cleanup-temp-uploads', name: 'admin_cleanup_temp_uploads_run', methods: ['POST'])]
216
    public function runCleanupTempUploads(
217
        Request          $request,
218
        TempUploadHelper $tempUploadHelper,
219
    ): Response {
220
        // CSRF
221
        $token = (string) $request->request->get('_token', '');
222
        if (!$this->isCsrfTokenValid('cleanup_temp_uploads', $token)) {
223
            throw $this->createAccessDeniedException('Invalid CSRF token.');
224
        }
225
226
        // Read inputs
227
        $olderThan = (int) ($request->request->get('older_than', 0));
228
        $dryRun    = (bool) $request->request->get('dry_run', false);
229
230
        // 1) Purge temp uploads/cache (configurable dir via helper parameter)
231
        $purge = $tempUploadHelper->purge(olderThanMinutes: $olderThan, dryRun: $dryRun);
232
233
        if ($dryRun) {
234
            $this->addFlash('success', sprintf(
235
                'DRY RUN: %d files (%.2f MB) would be removed from %s.',
236
                $purge['files'],
237
                $purge['bytes'] / 1048576,
238
                $tempUploadHelper->getTempDir()
239
            ));
240
        } else {
241
            $this->addFlash('success', sprintf(
242
                'Temporary uploads/cache cleaned: %d files removed (%.2f MB) in %s.',
243
                $purge['files'],
244
                $purge['bytes'] / 1048576,
245
                $tempUploadHelper->getTempDir()
246
            ));
247
        }
248
249
        // 2) Remove legacy build main.js and hashed variants (best effort)
250
        $publicBuild = $this->getParameter('kernel.project_dir').'/public/build';
251
        if (is_dir($publicBuild) && is_readable($publicBuild)) {
252
            @unlink($publicBuild.'/main.js');
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

252
            /** @scrutinizer ignore-unhandled */ @unlink($publicBuild.'/main.js');

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
253
            $files = @scandir($publicBuild) ?: [];
254
            foreach ($files as $f) {
255
                if (preg_match('/^main\..*\.js$/', $f)) {
256
                    @unlink($publicBuild.'/'.$f);
257
                }
258
            }
259
        }
260
261
        // 3) Rebuild styles/assets like original archive_cleanup.php
262
        try {
263
            ScriptHandler::dumpCssFiles();
264
            $this->addFlash('success', 'The styles and assets in the web/ folder have been refreshed.');
265
        } catch (\Throwable $e) {
266
            $this->addFlash('error', 'The styles and assets could not be refreshed. Ensure public/ is writable.');
267
            error_log($e->getMessage());
268
        }
269
270
        return $this->redirectToRoute('admin_cleanup_temp_uploads', [], Response::HTTP_SEE_OTHER);
271
    }
272
}
273