Passed
Push — master ( 2117d3...1baf8e )
by
unknown
14:08 queued 06:15
created

AttendanceController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 0
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 5
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chamilo\CoreBundle\Controller;
6
7
use Chamilo\CoreBundle\Entity\User;
8
use Chamilo\CoreBundle\Repository\Node\UserRepository;
9
use Chamilo\CourseBundle\Entity\CAttendance;
10
use Chamilo\CourseBundle\Entity\CAttendanceCalendar;
11
use Chamilo\CourseBundle\Entity\CAttendanceResult;
12
use Chamilo\CourseBundle\Entity\CAttendanceResultComment;
13
use Chamilo\CourseBundle\Entity\CAttendanceSheet;
14
use Chamilo\CourseBundle\Entity\CAttendanceSheetLog;
15
use Chamilo\CourseBundle\Repository\CAttendanceCalendarRepository;
16
use Chamilo\CourseBundle\Repository\CAttendanceSheetRepository;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
19
use Symfony\Component\HttpFoundation\JsonResponse;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\Routing\Attribute\Route;
22
use Symfony\Contracts\Translation\TranslatorInterface;
23
24
#[Route('/attendance')]
25
class AttendanceController extends AbstractController
26
{
27
28
    public function __construct(
29
        private readonly CAttendanceCalendarRepository $attendanceCalendarRepository,
30
        private readonly EntityManagerInterface $em,
31
        private readonly TranslatorInterface $translator
32
    ) {}
33
34
    #[Route('/full-data', name: 'chamilo_core_attendance_get_full_data', methods: ['GET'])]
35
    public function getFullAttendanceData(Request $request): JsonResponse
36
    {
37
        $attendanceId = (int) $request->query->get('attendanceId', 0);
38
39
        if (!$attendanceId) {
40
            return $this->json(['error' => 'Attendance ID is required'], 400);
41
        }
42
43
        $data = $this->attendanceCalendarRepository->findAttendanceWithData($attendanceId);
44
45
        return $this->json($data, 200);
46
    }
47
48
    #[Route('/users/context', name: 'chamilo_core_get_users_with_faults', methods: ['GET'])]
49
    public function getUsersWithFaults(
50
        Request $request,
51
        UserRepository $userRepository,
52
        CAttendanceCalendarRepository $calendarRepository,
53
        CAttendanceSheetRepository $sheetRepository
54
    ): JsonResponse {
55
        $courseId = (int) $request->query->get('courseId', 0);
56
        $sessionId = $request->query->get('sessionId') ? (int) $request->query->get('sessionId') : null;
57
        $groupId = $request->query->get('groupId') ? (int) $request->query->get('groupId') : null;
58
59
        if (!$courseId) {
60
            return $this->json(['error' => 'Course ID is required'], 400);
61
        }
62
63
        try {
64
            $users = $userRepository->findUsersByContext($courseId, $sessionId, $groupId);
65
66
            $totalCalendars = $calendarRepository->countByAttendanceAndGroup($courseId, $groupId);
67
68
            $formattedUsers = array_map(function ($user) use ($sheetRepository, $calendarRepository, $userRepository, $courseId, $groupId, $totalCalendars) {
0 ignored issues
show
Unused Code introduced by
The import $calendarRepository is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
69
                $userScore = $sheetRepository->getUserScore($user->getId(), $courseId, $groupId);
70
71
                $faults = max(0, $totalCalendars - $userScore);
72
                $faultsPercent = $totalCalendars > 0 ? round(($faults * 100) / $totalCalendars, 0) : 0;
73
74
                return [
75
                    'id' => $user->getId(),
76
                    'firstname' => $user->getFirstname(),
77
                    'lastname' => $user->getLastname(),
78
                    'email' => $user->getEmail(),
79
                    'username' => $user->getUsername(),
80
                    'photo' => $userRepository->getUserPicture($user->getId()),
81
                    'notAttended' => "$faults/$totalCalendars ({$faultsPercent}%)",
82
                ];
83
            }, $users);
84
85
            return $this->json($formattedUsers, 200);
86
        } catch (\Exception $e) {
87
            return $this->json(['error' => 'An error occurred: ' . $e->getMessage()], 500);
88
        }
89
    }
90
91
    #[Route('/sheet/save', name: 'chamilo_core_attendance_sheet_save', methods: ['POST'])]
92
    public function saveAttendanceSheet(
93
        Request $request,
94
        UserRepository $userRepository,
95
        CAttendanceSheetRepository $sheetRepository
96
    ): JsonResponse {
97
        $data = json_decode($request->getContent(), true);
98
99
        if (empty($data['attendanceData']) || empty($data['courseId'])) {
100
            return $this->json(['error' => 'Missing required parameters'], 400);
101
        }
102
103
        $attendanceData = $data['attendanceData'];
104
        $courseId = (int) $data['courseId'];
105
        $sessionId = isset($data['sessionId']) ? (int) $data['sessionId'] : null;
106
        $groupId = isset($data['groupId']) ? (int) $data['groupId'] : null;
107
108
        $usersInCourse = $userRepository->findUsersByContext($courseId, $sessionId, $groupId);
109
        $userIdsInCourse = array_map(fn(User $user) => $user->getId(), $usersInCourse);
110
111
        $affectedRows = 0;
112
113
        try {
114
            foreach ($attendanceData as $entry) {
115
                $userId = (int) $entry['userId'];
116
                $calendarId = (int) $entry['calendarId'];
117
                $presence = array_key_exists('presence', $entry) ? $entry['presence'] : null;
118
                $signature = $entry['signature'] ?? null;
119
                $comment = $entry['comment'] ?? null;
120
121
                $calendar = $this->attendanceCalendarRepository->find($calendarId);
122
                if (!$calendar) {
123
                    return $this->json(['error' => "Attendance calendar with ID $calendarId not found"], 404);
124
                }
125
126
                $user = $this->em->getRepository(User::class)->find($userId);
127
                if (!$user) {
128
                    continue;
129
                }
130
131
                $sheet = $sheetRepository->findOneBy([
132
                    'user' => $user,
133
                    'attendanceCalendar' => $calendar,
134
                ]);
135
136
                if ($sheet && $presence === null) {
137
                    $this->em->remove($sheet);
138
                    continue;
139
                }
140
141
                if (!$sheet && $presence === null) {
142
                    continue;
143
                }
144
145
                if (!$sheet) {
146
                    $sheet = new CAttendanceSheet();
147
                }
148
149
                $sheet->setUser($user)
150
                    ->setAttendanceCalendar($calendar)
151
                    ->setPresence($presence)
152
                    ->setSignature($signature);
153
154
                $this->em->persist($sheet);
155
156
                $this->em->flush();
157
158
                if ($comment !== null) {
159
                    $existingComment = $this->em->getRepository(CAttendanceResultComment::class)->findOneBy([
160
                        'attendanceSheetId' => $sheet->getIid(),
161
                        'userId' => $user->getId(),
162
                    ]);
163
164
                    if (!$existingComment) {
165
                        $existingComment = new CAttendanceResultComment();
166
                        $existingComment->setAttendanceSheetId($sheet->getIid());
167
                        $existingComment->setUserId($user->getId());
168
                        $existingComment->setAuthorUserId($this->getUser()->getId());
169
                    }
170
171
                    $existingComment->setComment($comment);
172
                    $existingComment->setUpdatedAt(new \DateTime());
173
174
                    $this->em->persist($existingComment);
175
                }
176
            }
177
178
            $calendarIds = array_unique(array_column($attendanceData, 'calendarId'));
179
            foreach ($calendarIds as $calendarId) {
180
                $calendar = $this->attendanceCalendarRepository->find($calendarId);
181
                if ($calendar && !$calendar->getDoneAttendance()) {
182
                    $calendar->setDoneAttendance(true);
183
                    $this->em->persist($calendar);
184
                }
185
            }
186
187
            $calendars = $this->attendanceCalendarRepository->findBy(['iid' => $calendarIds]);
188
            $attendance = $calendars[0]->getAttendance();
189
            $this->updateAttendanceResults($attendance);
190
191
            $lasteditType = $calendars[0]->getDoneAttendance()
192
                ? 'UPDATED_ATTENDANCE_LOG_TYPE'
193
                : 'DONE_ATTENDANCE_LOG_TYPE';
194
195
            foreach ($calendars as $calendar) {
196
                $this->saveAttendanceLog($attendance, $lasteditType, $calendar);
197
            }
198
199
            $this->em->flush();
200
201
            return $this->json([
202
                'message' => $this->translator->trans('Attendance data and comments saved successfully'),
203
                'affectedRows' => $affectedRows,
204
            ]);
205
206
        } catch (\Exception $e) {
207
            return $this->json(['error' => 'An error occurred: ' . $e->getMessage()], 500);
208
        }
209
    }
210
211
    private function updateAttendanceResults(CAttendance $attendance): void
212
    {
213
        $sheets = $attendance->getCalendars()->map(fn ($calendar) => $calendar->getSheets())->toArray();
214
        $results = [];
215
216
        foreach ($sheets as $calendarSheets) {
217
            foreach ($calendarSheets as $sheet) {
218
                $userId = $sheet->getUser()->getId();
219
                $results[$userId] = ($results[$userId] ?? 0) + $sheet->getPresence();
220
            }
221
        }
222
223
        foreach ($results as $userId => $score) {
224
            $user = $this->em->getRepository(User::class)->find($userId);
225
            if (!$user) {
226
                continue;
227
            }
228
229
            $result = $this->em->getRepository(CAttendanceResult::class)->findOneBy([
230
                'user' => $user,
231
                'attendance' => $attendance,
232
            ]);
233
234
            if (!$result) {
235
                $result = new CAttendanceResult();
236
                $result->setUser($user);
237
                $result->setAttendance($attendance);
238
            }
239
240
            $result->setScore((int) $score);
241
            $this->em->persist($result);
242
        }
243
    }
244
245
    private function saveAttendanceLog(CAttendance $attendance, string $lasteditType, CAttendanceCalendar $calendar): void
246
    {
247
        $log = new CAttendanceSheetLog();
248
        $log->setAttendance($attendance)
249
            ->setLasteditDate(new \DateTime())
250
            ->setLasteditType($lasteditType)
251
            ->setCalendarDateValue($calendar->getDateTime())
252
            ->setUser($this->getUser());
253
254
        $this->em->persist($log);
255
    }
256
}
257