Passed
Pull Request — master (#6257)
by
unknown
09:37
created

StudentPublicationController::editSubmission()   B

Complexity

Conditions 6
Paths 13

Size

Total Lines 49
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 27
nc 13
nop 5
dl 0
loc 49
rs 8.8657
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Controller;
8
9
use Chamilo\CoreBundle\Entity\Session;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\ServiceHelper\CidReqHelper;
12
use Chamilo\CoreBundle\ServiceHelper\MessageHelper;
13
use Chamilo\CourseBundle\Repository\CStudentPublicationRepository;
14
use Doctrine\ORM\EntityManagerInterface;
15
use Mpdf\Mpdf;
16
use Mpdf\MpdfException;
17
use Mpdf\Output\Destination;
18
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
19
use Symfony\Bundle\SecurityBundle\Security;
20
use Symfony\Component\HttpFoundation\JsonResponse;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\Routing\Annotation\Route;
24
use Symfony\Component\Serializer\SerializerInterface;
25
26
#[Route('/assignments')]
27
class StudentPublicationController extends AbstractController
28
{
29
    public function __construct(
30
        private readonly CStudentPublicationRepository $studentPublicationRepo,
31
        private readonly CidReqHelper $cidReqHelper
32
    ) {}
33
34
35
    #[Route('/student', name: 'chamilo_core_assignment_student_list', methods: ['GET'])]
36
    public function getStudentAssignments(SerializerInterface $serializer): JsonResponse
37
    {
38
        $course = $this->cidReqHelper->getCourseEntity();
39
        $session = $this->cidReqHelper->getSessionEntity();
40
41
        $assignments = $this->studentPublicationRepo->findVisibleAssignmentsForStudent($course, $session);
42
43
        $data = array_map(function ($row) use ($serializer) {
44
            $publication = $row[0] ?? null;
45
            $commentsCount = (int) ($row['commentsCount'] ?? 0);
46
            $correctionsCount = (int) ($row['correctionsCount'] ?? 0);
47
            $lastUpload = $row['lastUpload'] ?? null;
48
49
            $item = json_decode($serializer->serialize($publication, 'json', [
50
                'groups' => ['student_publication:read'],
51
            ]), true);
52
53
            $item['commentsCount'] = $commentsCount;
54
            $item['feedbackCount'] = $correctionsCount;
55
            $item['lastUpload'] = $lastUpload;
56
57
            return $item;
58
        }, $assignments);
59
60
        return new JsonResponse([
61
            'hydra:member' => $data,
62
            'hydra:totalItems' => count($data),
63
        ]);
64
    }
65
66
    #[Route('/progress', name: 'chamilo_core_assignment_student_progress', methods: ['GET'])]
67
    public function getStudentProgress(
68
        SerializerInterface $serializer
69
    ): JsonResponse {
70
        $course = $this->cidReqHelper->getCourseEntity();
71
        $session = $this->cidReqHelper->getSessionEntity();
72
73
        $progressList = $this->studentPublicationRepo->findStudentProgressByCourse($course, $session);
74
75
        return new JsonResponse([
76
            'hydra:member' => $progressList,
77
            'hydra:totalItems' => count($progressList),
78
        ]);
79
    }
80
81
    #[Route('/{assignmentId}/submissions', name: 'chamilo_core_assignment_student_submission_list', methods: ['GET'])]
82
    public function getAssignmentSubmissions(
83
        int $assignmentId,
84
        Request $request,
85
        SerializerInterface $serializer,
86
        CStudentPublicationRepository $repo,
87
        Security $security
88
    ): JsonResponse {
89
        /* @var User $user */
90
        $user = $security->getUser();
91
92
        $page = (int) $request->query->get('page', 1);
93
        $itemsPerPage = (int) $request->query->get('itemsPerPage', 10);
94
        $order = $request->query->all('order');
95
96
        [$submissions, $total] = $repo->findAssignmentSubmissionsPaginated(
97
            $assignmentId,
98
            $user,
99
            $page,
100
            $itemsPerPage,
101
            $order
102
        );
103
104
        $data = json_decode($serializer->serialize(
105
            $submissions,
106
            'json',
107
            ['groups' => ['student_publication:read']]
108
        ), true);
109
110
        return new JsonResponse([
111
            'hydra:member' => $data,
112
            'hydra:totalItems' => $total,
113
        ]);
114
    }
115
116
    #[Route('/{assignmentId}/submissions/teacher', name: 'chamilo_core_assignment_teacher_submission_list', methods: ['GET'])]
117
    public function getAssignmentSubmissionsForTeacher(
118
        int $assignmentId,
119
        Request $request,
120
        SerializerInterface $serializer,
121
        CStudentPublicationRepository $repo
122
    ): JsonResponse {
123
        $page = (int) $request->query->get('page', 1);
124
        $itemsPerPage = (int) $request->query->get('itemsPerPage', 10);
125
        $order = $request->query->all('order');
126
127
        [$submissions, $total] = $repo->findAllSubmissionsByAssignment(
128
            $assignmentId,
129
            $page,
130
            $itemsPerPage,
131
            $order
132
        );
133
134
        $data = json_decode($serializer->serialize(
135
            $submissions,
136
            'json',
137
            ['groups' => ['student_publication:read']]
138
        ), true);
139
140
        return new JsonResponse([
141
            'hydra:member' => $data,
142
            'hydra:totalItems' => $total,
143
        ]);
144
    }
145
146
    #[Route('/submissions/{id}', name: 'chamilo_core_assignment_student_submission_delete', methods: ['DELETE'])]
147
    public function deleteSubmission(
148
        int $id,
149
        EntityManagerInterface $em,
150
        CStudentPublicationRepository $repo
151
    ): JsonResponse {
152
        $submission = $repo->find($id);
153
154
        if (!$submission) {
155
            return new JsonResponse(['error' => 'Submission not found.'], 404);
156
        }
157
158
        $this->denyAccessUnlessGranted('DELETE', $submission->getResourceNode());
159
160
        $em->remove($submission->getResourceNode());
161
        $em->flush();
162
163
        return new JsonResponse(null, 204);
164
    }
165
166
    #[Route('/submissions/{id}/edit', name: 'chamilo_core_assignment_student_submission_edit', methods: ['PATCH'])]
167
    public function editSubmission(
168
        int $id,
169
        Request $request,
170
        EntityManagerInterface $em,
171
        CStudentPublicationRepository $repo,
172
        MessageHelper $messageHelper
173
    ): JsonResponse {
174
        $submission = $repo->find($id);
175
176
        if (!$submission) {
177
            return new JsonResponse(['error' => 'Submission not found.'], 404);
178
        }
179
180
        $this->denyAccessUnlessGranted('EDIT', $submission->getResourceNode());
181
182
        $data = json_decode($request->getContent(), true);
183
        $title = $data['title'] ?? null;
184
        $description = $data['description'] ?? null;
185
        $sendMail = $data['sendMail'] ?? false;
186
187
        if ($title !== null) {
188
            $submission->setTitle($title);
189
        }
190
        if ($description !== null) {
191
            $submission->setDescription($description);
192
        }
193
194
        $em->flush();
195
196
        if ($sendMail) {
197
            $user = $submission->getUser();
198
            if ($user) {
199
                $messageSubject = sprintf('Feedback updated for "%s"', $submission->getTitle());
200
                $messageContent = sprintf(
201
                    'There is a new feedback update for your submission "%s". Please check it on the platform.',
202
                    $submission->getTitle()
203
                );
204
205
                $messageHelper->sendMessageSimple(
206
                    $user->getId(),
207
                    $messageSubject,
208
                    $messageContent,
209
                    $this->getUser()->getId()
210
                );
211
            }
212
        }
213
214
        return new JsonResponse(['success' => true]);
215
    }
216
217
    #[Route('/submissions/{id}/move', name: 'chamilo_core_assignment_student_submission_move', methods: ['PATCH'])]
218
    public function moveSubmission(
219
        int $id,
220
        Request $request,
221
        EntityManagerInterface $em,
222
        CStudentPublicationRepository $repo
223
    ): JsonResponse {
224
        $submission = $repo->find($id);
225
226
        if (!$submission) {
227
            return new JsonResponse(['error' => 'Submission not found.'], 404);
228
        }
229
230
        $this->denyAccessUnlessGranted('EDIT', $submission->getResourceNode());
231
232
        $data = json_decode($request->getContent(), true);
233
        $newAssignmentId = $data['newAssignmentId'] ?? null;
234
235
        if (!$newAssignmentId) {
236
            return new JsonResponse(['error' => 'New assignment ID is required.'], 400);
237
        }
238
239
        $newParent = $repo->find($newAssignmentId);
240
241
        if (!$newParent) {
242
            return new JsonResponse(['error' => 'Target assignment not found.'], 404);
243
        }
244
245
        $submission->setPublicationParent($newParent);
246
247
        $em->flush();
248
249
        return new JsonResponse(['success' => true]);
250
    }
251
252
    #[Route('/{assignmentId}/unsubmitted-users', name: 'chamilo_core_assignment_unsubmitted_users', methods: ['GET'])]
253
    public function getUnsubmittedUsers(
254
        int $assignmentId,
255
        SerializerInterface $serializer,
256
        CStudentPublicationRepository $repo
257
    ): JsonResponse {
258
        $course = $this->cidReqHelper->getCourseEntity();
259
        $session = $this->cidReqHelper->getSessionEntity();
260
261
        $students = $session
262
            ? $session->getSessionRelCourseRelUsersByStatus($course, Session::STUDENT)
263
            : $course->getStudentSubscriptions();
264
265
        $studentIds = array_map(fn ($rel) => $rel->getUser()->getId(), $students->toArray());
266
267
        $submittedUserIds = $repo->findUserIdsWithSubmissions($assignmentId);
268
269
        $unsubmitted = array_filter(
270
            $students->toArray(),
271
            fn ($rel) => !in_array($rel->getUser()->getId(), $submittedUserIds, true)
272
        );
273
274
        $data = array_values(array_map(fn ($rel) => $rel->getUser(), $unsubmitted));
275
276
        return $this->json([
277
            'hydra:member' => $data,
278
            'hydra:totalItems' => count($data),
279
        ], 200, [], ['groups' => ['user:read']]);
280
    }
281
282
    #[Route('/{assignmentId}/unsubmitted-users/email', name: 'chamilo_core_assignment_unsubmitted_users_email', methods: ['POST'])]
283
    public function emailUnsubmittedUsers(
284
        int $assignmentId,
285
        CStudentPublicationRepository $repo,
286
        MessageHelper $messageHelper,
287
        Security $security
288
    ): JsonResponse {
289
        $course = $this->cidReqHelper->getCourseEntity();
290
        $session = $this->cidReqHelper->getSessionEntity();
291
292
        /* @var User $user */
293
        $user = $security->getUser();
294
        $senderId = $user?->getId();
295
296
        $students = $session
297
            ? $session->getSessionRelCourseRelUsersByStatus($course, Session::STUDENT)
298
            : $course->getStudentSubscriptions();
299
300
        $submittedUserIds = $repo->findUserIdsWithSubmissions($assignmentId);
301
302
        $unsubmitted = array_filter(
303
            $students->toArray(),
304
            fn ($rel) => !in_array($rel->getUser()->getId(), $submittedUserIds, true)
305
        );
306
307
        foreach ($unsubmitted as $rel) {
308
            $user = $rel->getUser();
309
            $messageHelper->sendMessageSimple(
310
                $user->getId(),
311
                "You have not submitted your assignment",
312
                "Please submit your assignment as soon as possible.",
313
                $senderId
314
            );
315
        }
316
317
        return new JsonResponse(['success' => true, 'sent' => count($unsubmitted)]);
318
    }
319
320
    #[Route('/{id}/export/pdf', name: 'chamilo_core_assignment_export_pdf', methods: ['GET'])]
321
    public function exportPdf(
322
        int $id,
323
        Request $request,
324
        CStudentPublicationRepository $repo
325
    ): Response {
326
        $course = $this->cidReqHelper->getCourseEntity();
327
        $session = $this->cidReqHelper->getSessionEntity();
328
329
        $assignment = $repo->find($id);
330
331
        if (!$assignment) {
332
            throw $this->createNotFoundException('Assignment not found');
333
        }
334
335
        [$submissions] = $repo->findAllSubmissionsByAssignment(
336
            assignmentId: $assignment->getIid(),
337
            page: 1,
338
            itemsPerPage: 10000
339
        );
340
341
        $html = $this->renderView('@ChamiloCore/Work/pdf_export.html.twig', [
342
            'assignment' => $assignment,
343
            'course' => $course,
344
            'session' => $session,
345
            'submissions' => $submissions,
346
        ]);
347
348
        try {
349
            $mpdf = new Mpdf([
350
                'tempDir' => api_get_path(SYS_ARCHIVE_PATH) . 'mpdf/',
351
            ]);
352
            $mpdf->WriteHTML($html);
353
354
            return new Response(
355
                $mpdf->Output('', Destination::INLINE),
356
                200,
357
                ['Content-Type' => 'application/pdf']
358
            );
359
        } catch (MpdfException $e) {
360
            throw new \RuntimeException('Failed to generate PDF: '.$e->getMessage(), 500, $e);
361
        }
362
    }
363
}
364