Passed
Pull Request — master (#6357)
by
unknown
08:17
created

SessionAdminController::listCompleted()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 67
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 42
c 1
b 0
f 0
nc 2
nop 3
dl 0
loc 67
rs 8.3146

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\Controller\BaseController;
10
use Chamilo\CoreBundle\Entity\Course;
11
use Chamilo\CoreBundle\Entity\GradebookCertificate;
12
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
13
use Chamilo\CoreBundle\Entity\SessionRelUser;
14
use Chamilo\CoreBundle\Helpers\AccessUrlHelper;
15
use Chamilo\CoreBundle\Entity\ExtraField;
16
use Chamilo\CoreBundle\Helpers\UserHelper;
17
use Chamilo\CoreBundle\Repository\ExtraFieldRepository;
18
use Chamilo\CoreBundle\Repository\ExtraFieldValuesRepository;
19
use Chamilo\CoreBundle\Repository\GradebookCertificateRepository;
20
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
21
use Chamilo\CoreBundle\Repository\Node\UserRepository;
22
use Chamilo\CoreBundle\Repository\SessionRelCourseRelUserRepository;
23
use Chamilo\CoreBundle\Settings\SettingsManager;
24
use DateTime;
25
use Doctrine\ORM\EntityManagerInterface;
26
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
27
use Symfony\Component\HttpFoundation\JsonResponse;
28
use Symfony\Component\HttpFoundation\Request;
29
use Symfony\Component\HttpFoundation\Response;
30
use Symfony\Component\Routing\Annotation\Route;
31
32
#[Security("is_granted('ROLE_ADMIN') or is_granted('ROLE_SESSION_MANAGER')")]
33
#[Route('/admin/sessionadmin')]
34
class SessionAdminController extends BaseController
35
{
36
    public function __construct(
37
        private readonly CourseRepository $courseRepository,
38
        private readonly AccessUrlHelper $accessUrlHelper,
39
        private readonly SettingsManager $settingsManager,
40
        private readonly UserHelper $userHelper
41
    ) {}
42
43
    #[Route('/courses', name: 'chamilo_core_admin_sessionadmin_courses', methods: ['GET'])]
44
    public function listCourses(): JsonResponse
45
    {
46
        $url     = $this->accessUrlHelper->getCurrent();
47
        $courses = $this->courseRepository->getCoursesByAccessUrl($url);
48
49
        $data = array_map(static function (Course $course) {
50
            return [
51
                'id'          => $course->getId(),
52
                'title'       => $course->getTitle(),
53
                'code' => $course->getCode(),
54
                'description' => $course->getDescription(),
55
                'visibility'  => $course->getVisibility(),
56
                'illustrationUrl' => method_exists($course, 'getIllustrationUrl')
57
                    ? $course->getIllustrationUrl()
58
                    : null,
59
            ];
60
        }, $courses);
61
62
        return $this->json($data);
63
    }
64
65
    #[Route('/courses/completed', name: 'chamilo_core_admin_sessionadmin_courses_completed', methods: ['GET'])]
66
    public function listCompleted(
67
        Request $request,
68
        GradebookCertificateRepository $repo,
69
        AccessUrlHelper $accessUrlHelper,
70
    ): JsonResponse {
71
        // Extract and validate pagination parameters from the query
72
        $offset = max(0, (int) $request->query->get('offset', 0));
73
        $limit  = max(1, (int) $request->query->get('limit', 50));
74
75
        // Determine current access URL context
76
        $url = $accessUrlHelper->getCurrent();
77
78
        // Retrieve certificates with associated session and course context
79
        $certs = $repo->findCertificatesWithContext($url->getId(), $offset, $limit);
80
81
        $user = $this->userHelper->getCurrent();
82
83
        $allowPublic = 'true' === $this->settingsManager->getSetting('course.allow_public_certificates', true);
84
        $allowSessionAdmin = 'true' === $this->settingsManager->getSetting('certificate.session_admin_can_download_all_certificates', true);
85
        $isSessionAdmin = $user && $user->hasRole('ROLE_SESSION_MANAGER');
86
87
        // Transform the certificate entities into a frontend-friendly structure
88
        $mapCertificate = function (GradebookCertificate $gc) use ($allowPublic, $allowSessionAdmin, $isSessionAdmin) {
89
            $sessionRel = $gc->getCategory()->getCourse()->getSessions()[0] ?? null;
90
            $session = $sessionRel?->getSession();
91
            $path = $gc->getPathCertificate();
92
93
            $hash = null;
94
            $downloadUrl = null;
95
            $isDownloadAllowed = false;
96
97
            if (!empty($path)) {
98
                $hash = pathinfo($path, PATHINFO_FILENAME);
99
                $downloadUrl = '/certificates/'.$hash.'.pdf';
0 ignored issues
show
Bug introduced by
Are you sure $hash of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

99
                $downloadUrl = '/certificates/'./** @scrutinizer ignore-type */ $hash.'.pdf';
Loading history...
100
                $isPublic = $allowPublic && $gc->getPublish();
101
                $isDownloadAllowed = $isPublic || ($isSessionAdmin && $allowSessionAdmin);
102
            }
103
104
            return [
105
                'id'        => $gc->getId(),
106
                'issuedAt'  => $gc->getCreatedAt()->format('Y-m-d H:i:s'),
107
                'user'      => [
108
                    'id'   => $gc->getUser()->getId(),
109
                    'name' => $gc->getUser()->getFullName(),
110
                ],
111
                'course'    => [
112
                    'id'    => $gc->getCategory()->getCourse()->getId(),
113
                    'title' => $gc->getCategory()->getCourse()->getTitle(),
114
                ],
115
                'session'   => $session ? [
116
                    'id'    => $session->getId(),
117
                    'title' => $session->getTitle(),
118
                ] : null,
119
                'downloadUrl'        => $downloadUrl,
120
                'isDownloadAllowed'  => $isDownloadAllowed,
121
            ];
122
        };
123
124
        $items = array_map($mapCertificate, $certs);
125
126
        // Return JSON response with pagination metadata and certificate list
127
        return $this->json([
128
            'items'  => $items,
129
            'offset' => $offset,
130
            'limit'  => $limit,
131
            'count'  => \count($items),
132
        ]);
133
    }
134
135
    #[Route('/courses/incomplete', name: 'chamilo_core_admin_sessionadmin_courses_incomplete', methods: ['GET'])]
136
    public function listIncomplete(
137
        GradebookCertificateRepository $repo,
138
        AccessUrlHelper $accessUrlHelper
139
    ): JsonResponse {
140
        $url = $accessUrlHelper->getCurrent();
141
        $results = $repo->findIncompleteCertificates($url->getId());
142
143
        $items = array_map(function (SessionRelUser $sru) {
144
            $user = $sru->getUser();
145
            $session = $sru->getSession();
146
147
            $courses = $session->getCourses();
148
            $courseItems = [];
149
150
            foreach ($courses as $src) {
151
                $course = $src->getCourse();
152
153
                $courseItems[] = [
154
                    'user' => [
155
                        'id'   => $user->getId(),
156
                        'name' => $user->getFullName(),
157
                    ],
158
                    'course' => [
159
                        'id'    => $course->getId(),
160
                        'title' => $course->getTitle(),
161
                    ],
162
                    'session' => [
163
                        'id'    => $session->getId(),
164
                        'title' => $session->getTitle(),
165
                        'startDate' => $session->getAccessStartDate()?->format('Y-m-d'),
166
                        'endDate'   => $session->getAccessEndDate()?->format('Y-m-d'),
167
                    ],
168
                ];
169
            }
170
171
            return $courseItems;
172
        }, $results);
173
174
        $flatItems = array_merge(...$items);
175
176
        return $this->json([
177
            'items' => $flatItems,
178
            'count' => count($flatItems),
179
        ]);
180
    }
181
182
    #[Route('/courses/restartable', name: 'chamilo_core_admin_sessionadmin_courses_restartable', methods: ['GET'])]
183
    public function listRestartables(
184
        Request $request,
185
        GradebookCertificateRepository $repo,
186
        AccessUrlHelper $accessUrlHelper
187
    ): JsonResponse {
188
        $offset = max(0,  (int) $request->query->get('offset', 0));
189
        $limit  = max(1,  (int) $request->query->get('limit', 10));
190
191
        $urlId  = $accessUrlHelper->getCurrent()->getId();
192
193
        /** @var SessionRelCourseRelUser[] $rows */
194
        $rows = $repo->findRestartableSessions($urlId, $offset, $limit);
195
196
        $items = array_map(static function (SessionRelCourseRelUser $srcu) {
197
            $session = $srcu->getSession();
198
            $course  = $srcu->getCourse();
199
            $user    = $srcu->getUser();
200
201
            return [
202
                'user'    => ['id' => $user->getId(),   'name' => $user->getFullName()],
203
                'course'  => ['id' => $course->getId(), 'title'=> $course->getTitle()],
204
                'session' => [
205
                    'id'      => $session->getId(),
206
                    'title'   => $session->getTitle(),
207
                    'endDate' => $session->getAccessEndDate()?->format('Y-m-d'),
208
                ],
209
            ];
210
        }, $rows);
211
212
        return $this->json([
213
            'items'  => $items,
214
            'offset' => $offset,
215
            'limit'  => $limit,
216
            'count'  => \count($items),
217
        ]);
218
    }
219
220
    #[Route('/courses/extend_week', name: 'chamilo_core_admin_sessionadmin_session_extend_one_week', methods: ['POST'])]
221
    public function extendSessionByWeek(Request $request, SessionRelCourseRelUserRepository $sessionRelCourseRelUserRepository, EntityManagerInterface $entityManager): JsonResponse
222
    {
223
        $data = json_decode($request->getContent(), true);
224
        $sessionId = (int) ($data['sessionId'] ?? 0);
225
        $userId    = (int) ($data['userId'] ?? 0);
226
        $courseId  = (int) ($data['courseId'] ?? 0);
227
228
        if (!$sessionId || !$userId || !$courseId) {
229
            return $this->json(['error' => 'Missing data'], Response::HTTP_BAD_REQUEST);
230
        }
231
232
        $rel = $sessionRelCourseRelUserRepository->findOneBy([
233
            'session' => $sessionId,
234
            'user' => $userId,
235
            'course' => $courseId,
236
        ]);
237
238
        if (!$rel) {
239
            return $this->json(['error' => 'Relation not found'], Response::HTTP_NOT_FOUND);
240
        }
241
242
        $session = $rel->getSession();
243
244
        $now = new DateTime('now');
245
        $currentEndDate = $session->getAccessEndDate();
246
247
        $baseDate = $now > $currentEndDate ? $now : $currentEndDate;
248
249
        $newEndDate = clone $baseDate;
250
        $newEndDate->modify('+1 week');
251
252
        $session->setAccessEndDate($newEndDate);
253
        $entityManager->flush();
254
255
        return $this->json(['success' => true, 'message' => 'Session extended by one week.', 'newEndDate' => $newEndDate->format('Y-m-d')]);
256
    }
257
258
    #[Route('/courses/{id}', name: 'chamilo_core_admin_sessionadmin_course_view', methods: ['GET'])]
259
    public function getCourseForSessionAdmin(int $id): JsonResponse
260
    {
261
        $course = $this->courseRepository->find($id);
262
263
        if (!$course) {
264
            return $this->json(['error' => 'Course not found'], Response::HTTP_NOT_FOUND);
265
        }
266
267
        return $this->json([
268
            'id' => $course->getId(),
269
            'title' => $course->getTitle(),
270
            'code' => $course->getCode(),
271
            'description' => $course->getDescription(),
272
            'illustrationUrl' => method_exists($course, 'getIllustrationUrl') ? $course->getIllustrationUrl() : null,
273
        ]);
274
    }
275
276
    #[Route('/users', name: 'chamilo_core_admin_sessionadmin_search_users', methods: ['GET'])]
277
    public function searchUsers(
278
        Request $request,
279
        UserRepository $userRepo,
280
        ExtraFieldRepository $extraFieldRepo,
281
        ExtraFieldValuesRepository $extraFieldValuesRepo,
282
        AccessUrlHelper $accessUrlHelper,
283
        SettingsManager $settingsManager,
284
    ): JsonResponse {
285
        $lastname = $request->query->get('lastname');
286
        $firstname = $request->query->get('firstname');
287
        $extraFilters = $request->query->all('extraFilters');
288
289
        $configuredExtraFieldVariable = $settingsManager->getSetting('platform.session_admin_user_subscription_search_extra_field_to_search', true);
290
291
        $filters = [];
292
        if ($lastname) {
293
            $filters['lastname'] = $lastname;
294
        }
295
        if ($firstname) {
296
            $filters['firstname'] = $firstname;
297
        }
298
        if ($configuredExtraFieldVariable && !empty($extraFilters[$configuredExtraFieldVariable])) {
299
            $filters['extraFilters'] = [
300
                $configuredExtraFieldVariable => $extraFilters[$configuredExtraFieldVariable],
301
            ];
302
        }
303
304
        $users = $userRepo->findUsersForSessionAdmin(
305
            $filters['lastname'] ?? null,
306
            $filters['firstname'] ?? null,
307
            $filters['extraFilters'] ?? [],
308
            $accessUrlHelper->getCurrent(),
309
        );
310
311
        $data = [];
312
        foreach ($users as $user) {
313
            $extraValue = $extraFieldValuesRepo->getValueByVariableAndItem(
314
                $configuredExtraFieldVariable,
315
                $user->getId(),
316
                ExtraField::USER_FIELD_TYPE
317
            );
318
319
            $extra[$configuredExtraFieldVariable] = $extraValue->getFieldValue();
320
321
            $data[] = [
322
                'id' => $user->getId(),
323
                'lastname' => $user->getLastname(),
324
                'firstname' => $user->getFirstname(),
325
                'fullname' => trim($user->getFirstname() . ' ' . $user->getLastname()),
326
                'email' => $user->getEmail(),
327
                'extra' => $extra,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $extra seems to be defined later in this foreach loop on line 319. Are you sure it is defined here?
Loading history...
328
            ];
329
        }
330
331
        return $this->json([
332
            'items' => $data,
333
        ]);
334
    }
335
}
336