Passed
Push — master ( 1c618d...c1c6b0 )
by Yannick
10:36 queued 02:52
created

SocialController::addUsersToGroup()   A

Complexity

Conditions 2
Paths 3

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 8
c 0
b 0
f 0
nc 3
nop 3
dl 0
loc 12
rs 10
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\ExtraField;
10
use Chamilo\CoreBundle\Entity\Legal;
11
use Chamilo\CoreBundle\Entity\Message;
12
use Chamilo\CoreBundle\Entity\MessageAttachment;
13
use Chamilo\CoreBundle\Entity\User;
14
use Chamilo\CoreBundle\Entity\Usergroup;
15
use Chamilo\CoreBundle\Entity\UserRelUser;
16
use Chamilo\CoreBundle\Repository\ExtraFieldOptionsRepository;
17
use Chamilo\CoreBundle\Repository\ExtraFieldRepository;
18
use Chamilo\CoreBundle\Repository\LanguageRepository;
19
use Chamilo\CoreBundle\Repository\LegalRepository;
20
use Chamilo\CoreBundle\Repository\MessageRepository;
21
use Chamilo\CoreBundle\Repository\Node\IllustrationRepository;
22
use Chamilo\CoreBundle\Repository\Node\MessageAttachmentRepository;
23
use Chamilo\CoreBundle\Repository\Node\UsergroupRepository;
24
use Chamilo\CoreBundle\Repository\Node\UserRepository;
25
use Chamilo\CoreBundle\Repository\TrackEOnlineRepository;
26
use Chamilo\CoreBundle\Serializer\UserToJsonNormalizer;
27
use Chamilo\CoreBundle\ServiceHelper\UserHelper;
28
use Chamilo\CoreBundle\Settings\SettingsManager;
29
use Chamilo\CourseBundle\Repository\CForumThreadRepository;
30
use DateTime;
31
use DateTimeInterface;
32
use Doctrine\ORM\EntityManagerInterface;
33
use Exception;
34
use ExtraFieldValue;
35
use MessageManager;
36
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
37
use Symfony\Component\HttpFoundation\File\UploadedFile;
38
use Symfony\Component\HttpFoundation\JsonResponse;
39
use Symfony\Component\HttpFoundation\Request;
40
use Symfony\Component\HttpFoundation\RequestStack;
41
use Symfony\Component\HttpFoundation\Response;
42
use Symfony\Component\Mailer\MailerInterface;
43
use Symfony\Component\Mime\Email;
44
use Symfony\Component\Routing\Attribute\Route;
45
use Symfony\Contracts\Translation\TranslatorInterface;
46
use UserManager;
47
48
#[Route('/social-network')]
49
class SocialController extends AbstractController
50
{
51
    public function __construct(
52
        private readonly UserHelper $userHelper,
53
    ) {}
54
55
    #[Route('/personal-data/{userId}', name: 'chamilo_core_social_personal_data')]
56
    public function getPersonalData(
57
        int $userId,
58
        SettingsManager $settingsManager,
59
        UserToJsonNormalizer $userToJsonNormalizer
60
    ): JsonResponse {
61
        $propertiesToJson = $userToJsonNormalizer->serializeUserData($userId);
62
        $properties = $propertiesToJson ? json_decode($propertiesToJson, true) : [];
63
64
        $officerData = [
65
            ['name' => $settingsManager->getSetting('profile.data_protection_officer_name')],
66
            ['role' => $settingsManager->getSetting('profile.data_protection_officer_role')],
67
            ['email' => $settingsManager->getSetting('profile.data_protection_officer_email')],
68
        ];
69
        $properties['officer_data'] = $officerData;
70
71
        $dataForVue = [
72
            'personalData' => $properties,
73
        ];
74
75
        return $this->json($dataForVue);
76
    }
77
78
    #[Route('/terms-and-conditions/{userId}', name: 'chamilo_core_social_terms')]
79
    public function getLegalTerms(
80
        int $userId,
81
        SettingsManager $settingsManager,
82
        TranslatorInterface $translator,
83
        LegalRepository $legalTermsRepo,
84
        UserRepository $userRepo,
85
        LanguageRepository $languageRepo
86
    ): JsonResponse {
87
        $user = $userRepo->find($userId);
88
        if (!$user) {
89
            return $this->json(['error' => 'User not found']);
90
        }
91
92
        $isoCode = $user->getLocale();
93
        $extraFieldValue = new ExtraFieldValue('user');
94
        $value = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'legal_accept');
95
        if ($value && !empty($value['value'])) {
96
            [$legalId, $legalLanguageId, $legalTime] = explode(':', $value['value']);
97
            $term = $legalTermsRepo->find($legalId);
98
        } else {
99
            $term = $this->getLastConditionByLanguage($languageRepo, $isoCode, $legalTermsRepo, $settingsManager);
100
        }
101
102
        if (!$term) {
103
            return $this->json(['error' => 'Terms not found']);
104
        }
105
106
        $termExtraFields = new ExtraFieldValue('terms_and_condition');
107
        $values = $termExtraFields->getAllValuesByItem($term->getId());
108
109
        $termsContent = [];
110
        foreach ($values as $value) {
111
            if (!empty($value['value'])) {
112
                $termsContent[] = [
113
                    'title' => $translator->trans($value['display_text'], [], 'messages', $isoCode),
114
                    'content' => $value['value'],
115
                ];
116
            }
117
        }
118
119
        if (empty($termsContent)) {
120
            $termsContent[] = [
121
                'title' => $translator->trans('Terms and Conditions', [], 'messages', $isoCode),
122
                'content' => $term->getContent(),
123
            ];
124
        }
125
126
        $formattedDate = new DateTime('@'.$term->getDate());
127
128
        $dataForVue = [
129
            'terms' => $termsContent,
130
            'date_text' => $translator->trans('PublicationDate', [], 'messages', $isoCode).': '.$formattedDate->format('Y-m-d H:i:s'),
131
        ];
132
133
        return $this->json($dataForVue);
134
    }
135
136
    #[Route('/legal-status/{userId}', name: 'chamilo_core_social_legal_status')]
137
    public function getLegalStatus(
138
        int $userId,
139
        SettingsManager $settingsManager,
140
        TranslatorInterface $translator,
141
        UserRepository $userRepo,
142
    ): JsonResponse {
143
        $allowTermsConditions = 'true' === $settingsManager->getSetting('registration.allow_terms_conditions');
144
145
        if (!$allowTermsConditions) {
146
            return $this->json([
147
                'message' => $translator->trans('No terms and conditions available', [], 'messages'),
148
            ]);
149
        }
150
151
        $user = $userRepo->find($userId);
152
        if (!$user) {
153
            return $this->json(['error' => 'User not found']);
154
        }
155
156
        $extraFieldValue = new ExtraFieldValue('user');
157
        $value = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'legal_accept');
158
159
        if (empty($value['value'])) {
160
            return $this->json([
161
                'isAccepted' => false,
162
                'message' => $translator->trans('Send legal agreement', [], 'messages'),
163
            ]);
164
        }
165
166
        [$legalId, $legalLanguageId, $legalTime] = explode(':', $value['value']);
167
        $dateTime = new DateTime("@$legalTime");
168
        $response = [
169
            'isAccepted' => true,
170
            'acceptDate' => $dateTime->format('Y-m-d H:i:s'),
171
            'message' => '',
172
        ];
173
174
        return $this->json($response);
175
    }
176
177
    #[Route('/send-legal-term', name: 'chamilo_core_social_send_legal_term')]
178
    public function sendLegalTerm(
179
        Request $request,
180
        SettingsManager $settingsManager,
181
        TranslatorInterface $translator,
182
        LegalRepository $legalTermsRepo,
183
        UserRepository $userRepo,
184
        LanguageRepository $languageRepo
185
    ): JsonResponse {
186
        $data = json_decode($request->getContent(), true);
187
        $userId = $data['userId'] ?? null;
188
189
        /** @var User $user */
190
        $user = $userRepo->find($userId);
191
        if (!$user) {
0 ignored issues
show
introduced by
$user is of type Chamilo\CoreBundle\Entity\User, thus it always evaluated to true.
Loading history...
192
            return $this->json(['error' => 'User not found']);
193
        }
194
195
        $isoCode = $user->getLocale();
196
197
        /** @var Legal $term */
198
        $term = $this->getLastConditionByLanguage($languageRepo, $isoCode, $legalTermsRepo, $settingsManager);
199
200
        if (!$term) {
0 ignored issues
show
introduced by
$term is of type Chamilo\CoreBundle\Entity\Legal, thus it always evaluated to true.
Loading history...
201
            return $this->json(['error' => 'Terms not found']);
202
        }
203
204
        $legalAcceptType = $term->getVersion().':'.$term->getLanguageId().':'.time();
205
        UserManager::update_extra_field_value(
206
            $userId,
207
            'legal_accept',
208
            $legalAcceptType
209
        );
210
211
        $bossList = UserManager::getStudentBossList($userId);
212
        if (!empty($bossList)) {
213
            $bossList = array_column($bossList, 'boss_id');
214
            foreach ($bossList as $bossId) {
215
                $subjectEmail = sprintf(
216
                    $translator->trans('User %s signed the agreement'),
217
                    $user->getFullname()
218
                );
219
                $contentEmail = sprintf(
220
                    $translator->trans('User %s signed the agreement.TheDateY'),
221
                    $user->getFullname(),
222
                    api_get_local_time()
223
                );
224
225
                MessageManager::send_message_simple(
226
                    $bossId,
227
                    $subjectEmail,
228
                    $contentEmail,
229
                    $userId
230
                );
231
            }
232
        }
233
234
        return $this->json([
235
            'success' => true,
236
            'message' => $translator->trans('Terms accepted successfully.'),
237
        ]);
238
    }
239
240
    #[Route('/delete-legal', name: 'chamilo_core_social_delete_legal')]
241
    public function deleteLegal(Request $request, TranslatorInterface $translator): JsonResponse
242
    {
243
        $data = json_decode($request->getContent(), true);
244
        $userId = $data['userId'] ?? null;
245
246
        if (!$userId) {
247
            return $this->json(['error' => $translator->trans('User ID not provided')], Response::HTTP_BAD_REQUEST);
248
        }
249
250
        $extraFieldValue = new ExtraFieldValue('user');
251
        $value = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'legal_accept');
252
        if ($value && isset($value['id'])) {
253
            $extraFieldValue->delete($value['id']);
254
        }
255
256
        $value = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'termactivated');
257
        if ($value && isset($value['id'])) {
258
            $extraFieldValue->delete($value['id']);
259
        }
260
261
        return $this->json(['success' => true, 'message' => $translator->trans('Legal acceptance revoked successfully.')]);
262
    }
263
264
    #[Route('/handle-privacy-request', name: 'chamilo_core_social_handle_privacy_request')]
265
    public function handlePrivacyRequest(
266
        Request $request,
267
        SettingsManager $settingsManager,
268
        UserRepository $userRepo,
269
        TranslatorInterface $translator,
270
        MailerInterface $mailer,
271
        RequestStack $requestStack
272
    ): JsonResponse {
273
        $data = json_decode($request->getContent(), true);
274
        $userId = $data['userId'] ? (int) $data['userId'] : null;
275
        $explanation = $data['explanation'] ?? '';
276
        $requestType = $data['requestType'] ?? '';
277
278
        /** @var User $user */
279
        $user = $userRepo->find($userId);
280
281
        if (!$user) {
0 ignored issues
show
introduced by
$user is of type Chamilo\CoreBundle\Entity\User, thus it always evaluated to true.
Loading history...
282
            return $this->json(['success' => false, 'message' => 'User not found']);
283
        }
284
285
        if ('delete_account' === $requestType) {
286
            $fieldToUpdate = 'request_for_delete_account';
287
            $justificationFieldToUpdate = 'request_for_delete_account_justification';
288
            $emailSubject = $translator->trans('Request for account deletion');
289
            $emailContent = sprintf($translator->trans('User %s asked for the deletion of his/her account, explaining that : ').$explanation, $user->getFullName());
290
        } elseif ('delete_legal' === $requestType) {
291
            $fieldToUpdate = 'request_for_legal_agreement_consent_removal';
292
            $justificationFieldToUpdate = 'request_for_legal_agreement_consent_removal_justification';
293
            $emailSubject = $translator->trans('Request for consent withdrawal on legal terms');
294
            $emailContent = sprintf($translator->trans('User %s asked for the removal of his/her consent to our legal terms, explaining that: ').$explanation, $user->getFullName());
295
        } else {
296
            return $this->json(['success' => false, 'message' => 'Invalid action type']);
297
        }
298
299
        UserManager::createDataPrivacyExtraFields();
300
        UserManager::update_extra_field_value($userId, $fieldToUpdate, 1);
301
        UserManager::update_extra_field_value($userId, $justificationFieldToUpdate, $explanation);
302
303
        $request = $requestStack->getCurrentRequest();
304
        $baseUrl = $request->getSchemeAndHttpHost().$request->getBasePath();
305
        $specificPath = '/main/admin/user_list_consent.php';
306
        $link = $baseUrl.$specificPath;
307
        $emailContent .= $translator->trans('Go here : ').'<a href="'.$link.'">'.$link.'</a>';
308
309
        $emailOfficer = $settingsManager->getSetting('profile.data_protection_officer_email');
310
        if (!empty($emailOfficer)) {
311
            $email = new Email();
312
            $email
313
                ->from($user->getEmail())
314
                ->to($emailOfficer)
315
                ->subject($emailSubject)
316
                ->html($emailContent)
317
            ;
318
            $mailer->send($email);
319
        } else {
320
            MessageManager::sendMessageToAllAdminUsers($user->getId(), $emailSubject, $emailContent);
321
        }
322
323
        return $this->json([
324
            'success' => true,
325
            'message' => $translator->trans('Your request has been received.'),
326
        ]);
327
    }
328
329
    #[Route('/groups/{userId}', name: 'chamilo_core_social_groups')]
330
    public function getGroups(
331
        int $userId,
332
        UsergroupRepository $usergroupRepository,
333
        CForumThreadRepository $forumThreadRepository,
334
        SettingsManager $settingsManager,
335
        RequestStack $requestStack
336
    ): JsonResponse {
337
        $baseUrl = $requestStack->getCurrentRequest()->getBaseUrl();
338
        $cid = (int) $settingsManager->getSetting('forum.global_forums_course_id');
339
        $items = [];
340
        $goToUrl = '';
341
342
        if (!empty($cid)) {
343
            $threads = $forumThreadRepository->getThreadsBySubscriptions($userId, $cid);
344
            foreach ($threads as $thread) {
345
                $threadId = $thread->getIid();
346
                $forumId = (int) $thread->getForum()->getIid();
347
                $items[] = [
348
                    'id' => $threadId,
349
                    'name' => $thread->getTitle(),
350
                    'description' => '',
351
                    'url' => $baseUrl.'/main/forum/viewthread.php?cid='.$cid.'&sid=0&gid=0&forum='.$forumId.'&thread='.$threadId,
352
                ];
353
            }
354
            $goToUrl = $baseUrl.'/main/forum/index.php?cid='.$cid.'&sid=0&gid=0';
355
        } else {
356
            $groups = $usergroupRepository->getGroupsByUser($userId);
357
            foreach ($groups as $group) {
358
                $items[] = [
359
                    'id' => $group->getId(),
360
                    'name' => $group->getTitle(),
361
                    'description' => $group->getDescription(),
362
                    'url' => $baseUrl.'/resources/usergroups/show/'.$group->getId(),
363
                ];
364
            }
365
        }
366
367
        return $this->json([
368
            'items' => $items,
369
            'go_to' => $goToUrl,
370
        ]);
371
    }
372
373
    #[Route('/group/{groupId}/discussion/{discussionId}/messages', name: 'chamilo_core_social_group_discussion_messages')]
374
    public function getDiscussionMessages(
375
        $groupId,
376
        $discussionId,
377
        MessageRepository $messageRepository,
378
        UserRepository $userRepository,
379
        MessageAttachmentRepository $attachmentRepository
380
    ): JsonResponse {
381
        $messages = $messageRepository->getMessagesByGroupAndMessage((int) $groupId, (int) $discussionId);
382
383
        $formattedMessages = $this->formatMessagesHierarchy($messages, $userRepository, $attachmentRepository);
384
385
        return $this->json($formattedMessages);
386
    }
387
388
    #[Route('/get-forum-link', name: 'get_forum_link')]
389
    public function getForumLink(
390
        SettingsManager $settingsManager,
391
        RequestStack $requestStack
392
    ): JsonResponse {
393
        $baseUrl = $requestStack->getCurrentRequest()->getBaseUrl();
394
        $cid = (int) $settingsManager->getSetting('forum.global_forums_course_id');
395
396
        $goToLink = '';
397
        if (!empty($cid)) {
398
            $goToLink = $baseUrl.'/main/forum/index.php?cid='.$cid.'&sid=0&gid=0';
399
        }
400
401
        return $this->json(['go_to' => $goToLink]);
402
    }
403
404
    #[Route('/invite-friends/{userId}/{groupId}', name: 'chamilo_core_social_invite_friends')]
405
    public function inviteFriends(
406
        int $userId,
407
        int $groupId,
408
        UserRepository $userRepository,
409
        UsergroupRepository $usergroupRepository,
410
        IllustrationRepository $illustrationRepository
411
    ): JsonResponse {
412
        $user = $userRepository->find($userId);
413
        if (!$user) {
414
            return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
415
        }
416
417
        $group = $usergroupRepository->find($groupId);
418
        if (!$group) {
419
            return $this->json(['error' => 'Group not found'], Response::HTTP_NOT_FOUND);
420
        }
421
422
        $friends = $userRepository->getFriendsNotInGroup($userId, $groupId);
423
424
        $friendsList = array_map(function ($friend) use ($illustrationRepository) {
425
            return [
426
                'id' => $friend->getId(),
427
                'name' => $friend->getFirstName().' '.$friend->getLastName(),
428
                'avatar' => $illustrationRepository->getIllustrationUrl($friend),
429
            ];
430
        }, $friends);
431
432
        return $this->json(['friends' => $friendsList]);
433
    }
434
435
    #[Route('/add-users-to-group/{groupId}', name: 'chamilo_core_social_add_users_to_group')]
436
    public function addUsersToGroup(Request $request, int $groupId, UsergroupRepository $usergroupRepository): JsonResponse
437
    {
438
        $data = json_decode($request->getContent(), true);
439
        $userIds = $data['userIds'] ?? [];
440
441
        try {
442
            $usergroupRepository->addUserToGroup($userIds, $groupId);
443
444
            return $this->json(['success' => true, 'message' => 'Users added to group successfully.']);
445
        } catch (Exception $e) {
446
            return $this->json(['success' => false, 'message' => 'An error occurred: '.$e->getMessage()], Response::HTTP_BAD_REQUEST);
447
        }
448
    }
449
450
    #[Route('/group/{groupId}/invited-users', name: 'chamilo_core_social_group_invited_users')]
451
    public function groupInvitedUsers(int $groupId, UsergroupRepository $usergroupRepository, IllustrationRepository $illustrationRepository): JsonResponse
452
    {
453
        $invitedUsers = $usergroupRepository->getInvitedUsersByGroup($groupId);
454
455
        $invitedUsersList = array_map(function ($user) {
456
            return [
457
                'id' => $user['id'],
458
                'name' => $user['username'],
459
                // 'avatar' => $illustrationRepository->getIllustrationUrl($user),
460
            ];
461
        }, $invitedUsers);
462
463
        return $this->json(['invitedUsers' => $invitedUsersList]);
464
    }
465
466
    #[Route('/user-profile/{userId}', name: 'chamilo_core_social_user_profile')]
467
    public function getUserProfile(
468
        int $userId,
469
        SettingsManager $settingsManager,
470
        LanguageRepository $languageRepository,
471
        UserRepository $userRepository,
472
        RequestStack $requestStack,
473
        TrackEOnlineRepository $trackOnlineRepository,
474
        ExtraFieldRepository $extraFieldRepository,
475
        ExtraFieldOptionsRepository $extraFieldOptionsRepository
476
    ): JsonResponse {
477
        $user = $userRepository->find($userId);
478
        if (!$user) {
479
            return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
480
        }
481
482
        $baseUrl = $requestStack->getCurrentRequest()->getBaseUrl();
483
        $profileFieldsVisibilityJson = $settingsManager->getSetting('profile.profile_fields_visibility');
484
        $profileFieldsVisibility = json_decode($profileFieldsVisibilityJson, true)['options'] ?? [];
485
486
        $vCardUserLink = $profileFieldsVisibility['vcard'] ?? true ? $baseUrl.'/main/social/vcard_export.php?userId='.(int) $userId : '';
487
488
        $languageInfo = null;
489
        if ($profileFieldsVisibility['language'] ?? true) {
490
            $language = $languageRepository->findByIsoCode($user->getLocale());
491
            if ($language) {
492
                $languageInfo = [
493
                    'label' => $language->getOriginalName(),
494
                    'value' => $language->getEnglishName(),
495
                    'code' => $language->getIsocode(),
496
                ];
497
            }
498
        }
499
500
        $isUserOnline = $trackOnlineRepository->isUserOnline($userId);
501
        $userOnlyInChat = $this->checkUserStatus($userId, $userRepository);
502
        $extraFields = $this->getExtraFieldBlock($userId, $userRepository, $settingsManager, $extraFieldRepository, $extraFieldOptionsRepository);
503
504
        $response = [
505
            'vCardUserLink' => $vCardUserLink,
506
            'language' => $languageInfo,
507
            'visibility' => $profileFieldsVisibility,
508
            'isUserOnline' => $isUserOnline,
509
            'userOnlyInChat' => $userOnlyInChat,
510
            'extraFields' => $extraFields,
511
        ];
512
513
        return $this->json($response);
514
    }
515
516
    private function getExtraFieldBlock(
517
        int $userId,
518
        UserRepository $userRepository,
519
        SettingsManager $settingsManager,
520
        ExtraFieldRepository $extraFieldRepository,
521
        ExtraFieldOptionsRepository $extraFieldOptionsRepository
522
    ): array {
523
        $user = $userRepository->find($userId);
524
        if (!$user) {
525
            return [];
526
        }
527
528
        $fieldVisibilityConfig = $settingsManager->getSetting('profile.profile_fields_visibility');
529
        $fieldVisibility = $fieldVisibilityConfig ? json_decode($fieldVisibilityConfig, true)['options'] : [];
530
531
        $extraUserData = $userRepository->getExtraUserData($userId);
532
        $extraFieldsFormatted = [];
533
        foreach ($extraUserData as $key => $value) {
534
            $fieldVariable = str_replace('extra_', '', $key);
535
536
            $extraField = $extraFieldRepository->getHandlerFieldInfoByFieldVariable($fieldVariable, ExtraField::USER_FIELD_TYPE);
537
            if (!$extraField || !isset($fieldVisibility[$fieldVariable]) || !$fieldVisibility[$fieldVariable]) {
538
                continue;
539
            }
540
541
            $fieldValue = \is_array($value) ? implode(', ', $value) : $value;
542
543
            switch ($extraField['type']) {
544
                case ExtraField::FIELD_TYPE_RADIO:
545
                case ExtraField::FIELD_TYPE_SELECT:
546
                    $extraFieldOptions = $extraFieldOptionsRepository->getFieldOptionByFieldAndOption($extraField['id'], $fieldValue, ExtraField::USER_FIELD_TYPE);
547
                    if (!empty($extraFieldOptions)) {
548
                        $optionTexts = array_map(function ($option) {
549
                            return $option['display_text'];
550
                        }, $extraFieldOptions);
551
                        $fieldValue = implode(', ', $optionTexts);
552
                    }
553
554
                    break;
555
556
                case ExtraField::FIELD_TYPE_GEOLOCALIZATION_COORDINATES:
557
                case ExtraField::FIELD_TYPE_GEOLOCALIZATION:
558
                    $geoData = explode('::', $fieldValue);
559
                    $locationName = $geoData[0];
560
                    $coordinates = $geoData[1] ?? '';
561
                    $fieldValue = $locationName;
562
563
                    break;
564
            }
565
566
            $extraFieldsFormatted[] = [
567
                'variable' => $fieldVariable,
568
                'label' => $extraField['display_text'],
569
                'value' => $fieldValue,
570
            ];
571
        }
572
573
        return $extraFieldsFormatted;
574
    }
575
576
    #[Route('/invitations/{userId}', name: 'chamilo_core_social_invitations')]
577
    public function getInvitations(
578
        int $userId,
579
        MessageRepository $messageRepository,
580
        UsergroupRepository $usergroupRepository,
581
        UserRepository $userRepository,
582
        TranslatorInterface $translator
583
    ): JsonResponse {
584
        $user = $this->userHelper->getCurrent();
585
        if ($userId !== $user->getId()) {
586
            return $this->json(['error' => 'Unauthorized'], Response::HTTP_UNAUTHORIZED);
587
        }
588
589
        $receivedMessages = $messageRepository->findReceivedInvitationsByUser($user);
590
        $receivedInvitations = [];
591
        foreach ($receivedMessages as $message) {
592
            $sender = $message->getSender();
593
            $receivedInvitations[] = [
594
                'id' => $message->getId(),
595
                'itemId' => $sender->getId(),
596
                'itemName' => $sender->getFirstName().' '.$sender->getLastName(),
597
                'itemPicture' => $userRepository->getUserPicture($sender->getId()),
598
                'content' => $message->getContent(),
599
                'date' => $message->getSendDate()->format('Y-m-d H:i:s'),
600
                'canAccept' => true,
601
                'canDeny' => true,
602
            ];
603
        }
604
605
        $sentMessages = $messageRepository->findSentInvitationsByUser($user);
606
        $sentInvitations = [];
607
        foreach ($sentMessages as $message) {
608
            foreach ($message->getReceivers() as $receiver) {
609
                $receiverUser = $receiver->getReceiver();
610
                $sentInvitations[] = [
611
                    'id' => $message->getId(),
612
                    'itemId' => $receiverUser->getId(),
613
                    'itemName' => $receiverUser->getFirstName().' '.$receiverUser->getLastName(),
614
                    'itemPicture' => $userRepository->getUserPicture($receiverUser->getId()),
615
                    'content' => $message->getContent(),
616
                    'date' => $message->getSendDate()->format('Y-m-d H:i:s'),
617
                    'canAccept' => false,
618
                    'canDeny' => false,
619
                ];
620
            }
621
        }
622
623
        $pendingGroupInvitations = [];
624
        $pendingGroups = $usergroupRepository->getGroupsByUser($userId, Usergroup::GROUP_USER_PERMISSION_PENDING_INVITATION);
625
626
        /** @var Usergroup $group */
627
        foreach ($pendingGroups as $group) {
628
            $isGroupVisible = 1 === (int) $group->getVisibility();
629
            $infoVisibility = !$isGroupVisible ? ' - '.$translator->trans('This group is closed.') : '';
630
            $pendingGroupInvitations[] = [
631
                'id' => $group->getId(),
632
                'itemId' => $group->getId(),
633
                'itemName' => $group->getTitle().$infoVisibility,
634
                'itemPicture' => $usergroupRepository->getUsergroupPicture($group->getId()),
635
                'content' => $group->getDescription(),
636
                'date' => $group->getCreatedAt()->format('Y-m-d H:i:s'),
637
                'canAccept' => $isGroupVisible,
638
                'canDeny' => true,
639
            ];
640
        }
641
642
        return $this->json([
643
            'receivedInvitations' => $receivedInvitations,
644
            'sentInvitations' => $sentInvitations,
645
            'pendingGroupInvitations' => $pendingGroupInvitations,
646
        ]);
647
    }
648
649
    #[Route('/invitations/count/{userId}', name: 'chamilo_core_social_invitations_count')]
650
    public function getInvitationsCount(
651
        int $userId,
652
        MessageRepository $messageRepository,
653
        UsergroupRepository $usergroupRepository
654
    ): JsonResponse {
655
        $user = $this->userHelper->getCurrent();
656
        if ($userId !== $user->getId()) {
657
            return $this->json(['error' => 'Unauthorized']);
658
        }
659
660
        $receivedMessagesCount = \count($messageRepository->findReceivedInvitationsByUser($user));
661
        $pendingGroupInvitationsCount = \count($usergroupRepository->getGroupsByUser($userId, Usergroup::GROUP_USER_PERMISSION_PENDING_INVITATION));
662
        $totalInvitationsCount = $receivedMessagesCount + $pendingGroupInvitationsCount;
663
664
        return $this->json(['totalInvitationsCount' => $totalInvitationsCount]);
665
    }
666
667
    #[Route('/search', name: 'chamilo_core_social_search')]
668
    public function search(
669
        Request $request,
670
        UserRepository $userRepository,
671
        UsergroupRepository $usergroupRepository,
672
        TrackEOnlineRepository $trackOnlineRepository,
673
        MessageRepository $messageRepository
674
    ): JsonResponse {
675
        $query = $request->query->get('query', '');
676
        $type = $request->query->get('type', 'user');
677
        $from = $request->query->getInt('from', 0);
678
        $numberOfItems = $request->query->getInt('number_of_items', 1000);
679
680
        $formattedResults = [];
681
        if ('user' === $type) {
682
            $user = $this->userHelper->getCurrent();
683
            $results = $userRepository->searchUsersByTags($query, $user->getId(), 0, $from, $numberOfItems);
684
            foreach ($results as $item) {
685
                $isUserOnline = $trackOnlineRepository->isUserOnline($item['id']);
686
                $relation = $userRepository->getUserRelationWithType($user->getId(), $item['id']);
687
                $userReceiver = $userRepository->find($item['id']);
688
                $existingInvitations = $messageRepository->existingInvitations($user, $userReceiver);
689
                $formattedResults[] = [
690
                    'id' => $item['id'],
691
                    'name' => $item['firstname'].' '.$item['lastname'],
692
                    'avatar' => $userRepository->getUserPicture($item['id']),
693
                    'role' => 5 === $item['status'] ? 'student' : 'teacher',
694
                    'status' => $isUserOnline ? 'online' : 'offline',
695
                    'url' => '/social?id='.$item['id'],
696
                    'relationType' => $relation['relationType'] ?? null,
697
                    'existingInvitations' => $existingInvitations,
698
                ];
699
            }
700
        } elseif ('group' === $type) {
701
            // Perform group search
702
            $results = $usergroupRepository->searchGroupsByTags($query, $from, $numberOfItems);
703
            foreach ($results as $item) {
704
                $formattedResults[] = [
705
                    'id' => $item['id'],
706
                    'name' => $item['title'],
707
                    'description' => $item['description'] ?? '',
708
                    'image' => $usergroupRepository->getUsergroupPicture($item['id']),
709
                    'url' => '/resources/usergroups/show/'.$item['id'],
710
                ];
711
            }
712
        }
713
714
        return $this->json(['results' => $formattedResults]);
715
    }
716
717
    #[Route('/group-details/{groupId}', name: 'chamilo_core_social_group_details')]
718
    public function groupDetails(
719
        int $groupId,
720
        UsergroupRepository $usergroupRepository,
721
        TrackEOnlineRepository $trackOnlineRepository
722
    ): JsonResponse {
723
        $user = $this->userHelper->getCurrent();
724
        if (!$user) {
725
            return $this->json(['error' => 'User not authenticated'], Response::HTTP_UNAUTHORIZED);
726
        }
727
728
        /** @var Usergroup $group */
729
        $group = $usergroupRepository->find($groupId);
730
        if (!$group) {
0 ignored issues
show
introduced by
$group is of type Chamilo\CoreBundle\Entity\Usergroup, thus it always evaluated to true.
Loading history...
731
            return $this->json(['error' => 'Group not found'], Response::HTTP_NOT_FOUND);
732
        }
733
734
        $isMember = $usergroupRepository->isGroupMember($groupId, $user);
735
        $role = $usergroupRepository->getUserGroupRole($groupId, $user->getId());
736
        $isUserOnline = $trackOnlineRepository->isUserOnline($user->getId());
737
        $isModerator = $usergroupRepository->isGroupModerator($groupId, $user->getId());
738
739
        $groupDetails = [
740
            'id' => $group->getId(),
741
            'title' => $group->getTitle(),
742
            'description' => $group->getDescription(),
743
            'url' => $group->getUrl(),
744
            'image' => $usergroupRepository->getUsergroupPicture($group->getId()),
745
            'visibility' => (int) $group->getVisibility(),
746
            'allowMembersToLeaveGroup' => $group->getAllowMembersToLeaveGroup(),
747
            'isMember' => $isMember,
748
            'isModerator' => $isModerator,
749
            'role' => $role,
750
            'isUserOnline' => $isUserOnline,
751
            'isAllowedToLeave' => 1 === $group->getAllowMembersToLeaveGroup(),
752
        ];
753
754
        return $this->json($groupDetails);
755
    }
756
757
    #[Route('/group-action', name: 'chamilo_core_social_group_action')]
758
    public function group(
759
        Request $request,
760
        UsergroupRepository $usergroupRepository,
761
        EntityManagerInterface $em,
762
        MessageRepository $messageRepository
763
    ): JsonResponse {
764
        if (str_starts_with($request->headers->get('Content-Type'), 'multipart/form-data')) {
765
            $userId = $request->request->get('userId');
766
            $groupId = $request->request->get('groupId');
767
            $action = $request->request->get('action');
768
            $title = $request->request->get('title', '');
769
            $content = $request->request->get('content', '');
770
            $parentId = $request->request->get('parentId', 0);
771
            $editMessageId = $request->request->get('messageId', 0);
772
773
            $structuredFiles = [];
774
            if ($request->files->has('files')) {
775
                $files = $request->files->get('files');
776
                foreach ($files as $file) {
777
                    $structuredFiles[] = [
778
                        'name' => $file->getClientOriginalName(),
779
                        'full_path' => $file->getRealPath(),
780
                        'type' => $file->getMimeType(),
781
                        'tmp_name' => $file->getPathname(),
782
                        'error' => $file->getError(),
783
                        'size' => $file->getSize(),
784
                    ];
785
                }
786
            }
787
        } else {
788
            $data = json_decode($request->getContent(), true);
789
            $userId = $data['userId'] ?? null;
790
            $groupId = $data['groupId'] ?? null;
791
            $action = $data['action'] ?? null;
792
        }
793
794
        if (!$userId || !$groupId || !$action) {
795
            return $this->json(['error' => 'Missing parameters'], Response::HTTP_BAD_REQUEST);
796
        }
797
798
        try {
799
            switch ($action) {
800
                case 'accept':
801
                    $userRole = $usergroupRepository->getUserGroupRole($groupId, $userId);
802
                    if (\in_array(
803
                        $userRole,
804
                        [
805
                            Usergroup::GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER,
806
                            Usergroup::GROUP_USER_PERMISSION_PENDING_INVITATION,
807
                        ]
808
                    )) {
809
                        $usergroupRepository->updateUserRole($userId, $groupId, Usergroup::GROUP_USER_PERMISSION_READER);
810
                    }
811
812
                    break;
813
814
                case 'join':
815
                    $usergroupRepository->addUserToGroup($userId, $groupId);
816
817
                    break;
818
819
                case 'deny':
820
                    $usergroupRepository->removeUserFromGroup($userId, $groupId, false);
821
822
                    break;
823
824
                case 'leave':
825
                    $usergroupRepository->removeUserFromGroup($userId, $groupId);
826
827
                    break;
828
829
                case 'reply_message_group':
830
                    $title = $title ?: substr(strip_tags($content), 0, 50);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $title does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $content does not seem to be defined for all execution paths leading up to this point.
Loading history...
831
832
                    // no break
833
                case 'edit_message_group':
834
                case 'add_message_group':
835
                    $res = MessageManager::send_message(
836
                        $userId,
837
                        $title,
838
                        $content,
839
                        $structuredFiles,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $structuredFiles does not seem to be defined for all execution paths leading up to this point.
Loading history...
840
                        [],
841
                        $groupId,
842
                        $parentId,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parentId does not seem to be defined for all execution paths leading up to this point.
Loading history...
843
                        $editMessageId,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $editMessageId does not seem to be defined for all execution paths leading up to this point.
Loading history...
844
                        0,
845
                        $userId,
846
                        false,
847
                        0,
848
                        false,
849
                        false,
850
                        Message::MESSAGE_TYPE_GROUP
851
                    );
852
853
                    break;
854
855
                case 'delete_message_group':
856
                    $messageId = $data['messageId'] ?? null;
857
858
                    if (!$messageId) {
859
                        return $this->json(['error' => 'Missing messageId parameter'], Response::HTTP_BAD_REQUEST);
860
                    }
861
862
                    $messageRepository->deleteTopicAndChildren($groupId, $messageId);
863
864
                    break;
865
866
                default:
867
                    return $this->json(['error' => 'Invalid action'], Response::HTTP_BAD_REQUEST);
868
            }
869
870
            $em->flush();
871
872
            return $this->json(['success' => 'Action completed successfully']);
873
        } catch (Exception $e) {
874
            return $this->json(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
875
        }
876
    }
877
878
    #[Route('/user-action', name: 'chamilo_core_social_user_action')]
879
    public function user(
880
        Request $request,
881
        UserRepository $userRepository,
882
        MessageRepository $messageRepository,
883
        EntityManagerInterface $em
884
    ): JsonResponse {
885
        $data = json_decode($request->getContent(), true);
886
887
        $userId = $data['userId'] ?? null;
888
        $targetUserId = $data['targetUserId'] ?? null;
889
        $action = $data['action'] ?? null;
890
        $isMyFriend = $data['is_my_friend'] ?? false;
891
        $subject = $data['subject'] ?? '';
892
        $content = $data['content'] ?? '';
893
894
        if (!$userId || !$targetUserId || !$action) {
895
            return $this->json(['error' => 'Missing parameters']);
896
        }
897
898
        $currentUser = $userRepository->find($userId);
899
        $friendUser = $userRepository->find($targetUserId);
900
901
        if (null === $currentUser || null === $friendUser) {
902
            return $this->json(['error' => 'User not found']);
903
        }
904
905
        try {
906
            switch ($action) {
907
                case 'send_invitation':
908
                    $result = $messageRepository->sendInvitationToFriend($currentUser, $friendUser, $subject, $content);
909
                    if (!$result) {
910
                        return $this->json(['error' => 'Invitation already exists or could not be sent']);
911
                    }
912
913
                    break;
914
915
                case 'send_message':
916
                    $result = MessageManager::send_message($friendUser->getId(), $subject, $content);
917
918
                    break;
919
920
                case 'add_friend':
921
                    $relationType = $isMyFriend ? UserRelUser::USER_RELATION_TYPE_FRIEND : UserRelUser::USER_UNKNOWN;
922
923
                    $userRepository->relateUsers($currentUser, $friendUser, $relationType);
924
                    $userRepository->relateUsers($friendUser, $currentUser, $relationType);
925
926
                    $messageRepository->invitationAccepted($friendUser, $currentUser);
927
928
                    break;
929
930
                case 'deny_friend':
931
                    $messageRepository->invitationDenied($friendUser, $currentUser);
932
933
                    break;
934
935
                default:
936
                    return $this->json(['error' => 'Invalid action']);
937
            }
938
939
            $em->flush();
940
941
            return $this->json(['success' => 'Action completed successfully']);
942
        } catch (Exception $e) {
943
            return $this->json(['error' => $e->getMessage()], Response::HTTP_INTERNAL_SERVER_ERROR);
944
        }
945
    }
946
947
    #[Route('/user-relation/{currentUserId}/{profileUserId}', name: 'chamilo_core_social_get_user_relation')]
948
    public function getUserRelation(int $currentUserId, int $profileUserId, EntityManagerInterface $em): JsonResponse
949
    {
950
        $isAllowed = $this->checkUserRelationship($currentUserId, $profileUserId, $em);
951
952
        return $this->json([
953
            'isAllowed' => $isAllowed,
954
        ]);
955
    }
956
957
    #[Route('/online-status', name: 'chamilo_core_social_get_online_status', methods: ['POST'])]
958
    public function getOnlineStatus(Request $request, TrackEOnlineRepository $trackOnlineRepository): JsonResponse
959
    {
960
        $data = json_decode($request->getContent(), true);
961
        $userIds = $data['userIds'] ?? [];
962
963
        $onlineStatuses = [];
964
        foreach ($userIds as $userId) {
965
            $onlineStatuses[$userId] = $trackOnlineRepository->isUserOnline($userId);
966
        }
967
968
        return $this->json($onlineStatuses);
969
    }
970
971
    #[Route('/upload-group-picture/{groupId}', name: 'chamilo_core_social_upload_group_picture')]
972
    public function uploadGroupPicture(
973
        Request $request,
974
        int $groupId,
975
        UsergroupRepository $usergroupRepository,
976
        IllustrationRepository $illustrationRepository
977
    ): JsonResponse {
978
        $file = $request->files->get('picture');
979
        if ($file instanceof UploadedFile) {
980
            $userGroup = $usergroupRepository->find($groupId);
981
            $illustrationRepository->addIllustration($userGroup, $this->userHelper->getCurrent(), $file);
982
        }
983
984
        return new JsonResponse(['success' => 'Group and image saved successfully'], Response::HTTP_OK);
985
    }
986
987
    #[Route('/terms-restrictions/{userId}', name: 'chamilo_core_social_terms_restrictions')]
988
    public function checkTermsRestrictions(
989
        int $userId,
990
        UserRepository $userRepo,
991
        ExtraFieldRepository $extraFieldRepository,
992
        TranslatorInterface $translator,
993
        SettingsManager $settingsManager
994
    ): JsonResponse {
995
        /** @var User $user */
996
        $user = $userRepo->find($userId);
997
998
        if (!$user) {
0 ignored issues
show
introduced by
$user is of type Chamilo\CoreBundle\Entity\User, thus it always evaluated to true.
Loading history...
999
            return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
1000
        }
1001
1002
        $isAdmin = $user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_SUPER_ADMIN');
1003
1004
        $termActivated = false;
1005
        $blockButton = false;
1006
        $infoMessage = '';
1007
1008
        if (!$isAdmin) {
1009
            if ('true' === $settingsManager->getSetting('ticket.show_terms_if_profile_completed')) {
1010
                $extraFieldValue = new ExtraFieldValue('user');
1011
                $value = $extraFieldValue->get_values_by_handler_and_field_variable($userId, 'termactivated');
1012
                if (isset($value['value'])) {
1013
                    $termActivated = !empty($value['value']) && 1 === (int) $value['value'];
1014
                }
1015
1016
                if (false === $termActivated) {
1017
                    $blockButton = true;
1018
                    $infoMessage .= $translator->trans('The terms and conditions have not yet been validated by your tutor.').'&nbsp;';
1019
                }
1020
1021
                if (!$user->isProfileCompleted()) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $user->isProfileCompleted() of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
1022
                    $blockButton = true;
1023
                    $infoMessage .= $translator->trans('You must first fill your profile to enable the terms and conditions validation.');
1024
                }
1025
            }
1026
        }
1027
1028
        return $this->json([
1029
            'blockButton' => $blockButton,
1030
            'infoMessage' => $infoMessage,
1031
        ]);
1032
    }
1033
1034
    /**
1035
     * Formats a hierarchical structure of messages for display.
1036
     *
1037
     * This function takes an array of Message entities and recursively formats them into a hierarchical structure.
1038
     * Each message is formatted with details such as user information, creation date, content, and attachments.
1039
     * The function also assigns a level to each message based on its depth in the hierarchy for display purposes.
1040
     */
1041
    private function formatMessagesHierarchy(array $messages, UserRepository $userRepository, MessageAttachmentRepository $attachmentRepository, ?int $parentId = null, int $level = 0): array
1042
    {
1043
        $formattedMessages = [];
1044
1045
        /** @var Message $message */
1046
        foreach ($messages as $message) {
1047
            if (($message->getParent() ? $message->getParent()->getId() : null) === $parentId) {
1048
                $attachments = $message->getAttachments();
1049
                $attachmentsUrls = [];
1050
                $attachmentSize = 0;
1051
                if ($attachments) {
1052
                    /** @var MessageAttachment $attachment */
1053
                    foreach ($attachments as $attachment) {
1054
                        $attachmentsUrls[] = [
1055
                            'link' => $attachmentRepository->getResourceFileDownloadUrl($attachment),
1056
                            'filename' => $attachment->getFilename(),
1057
                            'size' => $attachment->getSize(),
1058
                        ];
1059
                        $attachmentSize += $attachment->getSize();
1060
                    }
1061
                }
1062
                $formattedMessage = [
1063
                    'id' => $message->getId(),
1064
                    'user' => $message->getSender()->getFullName(),
1065
                    'created' => $message->getSendDate()->format(DateTimeInterface::ATOM),
1066
                    'title' => $message->getTitle(),
1067
                    'content' => $message->getContent(),
1068
                    'parentId' => $message->getParent() ? $message->getParent()->getId() : null,
1069
                    'avatar' => $userRepository->getUserPicture($message->getSender()->getId()),
1070
                    'senderId' => $message->getSender()->getId(),
1071
                    'attachment' => $attachmentsUrls ?? null,
1072
                    'attachmentSize' => $attachmentSize > 0 ? $attachmentSize : null,
1073
                    'level' => $level,
1074
                ];
1075
1076
                $children = $this->formatMessagesHierarchy($messages, $userRepository, $attachmentRepository, $message->getId(), $level + 1);
1077
                if (!empty($children)) {
1078
                    $formattedMessage['children'] = $children;
1079
                }
1080
1081
                $formattedMessages[] = $formattedMessage;
1082
            }
1083
        }
1084
1085
        return $formattedMessages;
1086
    }
1087
1088
    /**
1089
     * Checks the relationship between the current user and another user.
1090
     *
1091
     * This method first checks for a direct relationship between the two users. If no direct relationship is found,
1092
     * it then checks for indirect relationships through common friends (friends of friends).
1093
     */
1094
    private function checkUserRelationship(int $currentUserId, int $otherUserId, EntityManagerInterface $em): bool
1095
    {
1096
        if ($currentUserId === $otherUserId) {
1097
            return true;
1098
        }
1099
1100
        $relation = $em->getRepository(UserRelUser::class)
1101
            ->findOneBy([
1102
                'relationType' => [
1103
                    UserRelUser::USER_RELATION_TYPE_FRIEND,
1104
                    UserRelUser::USER_RELATION_TYPE_GOODFRIEND,
1105
                ],
1106
                'friend' => $otherUserId,
1107
                'user' => $currentUserId,
1108
            ])
1109
        ;
1110
1111
        if (null !== $relation) {
1112
            return true;
1113
        }
1114
1115
        $friendsOfCurrentUser = $em->getRepository(UserRelUser::class)
1116
            ->findBy([
1117
                'relationType' => [
1118
                    UserRelUser::USER_RELATION_TYPE_FRIEND,
1119
                    UserRelUser::USER_RELATION_TYPE_GOODFRIEND,
1120
                ],
1121
                'user' => $currentUserId,
1122
            ])
1123
        ;
1124
1125
        foreach ($friendsOfCurrentUser as $friendRelation) {
1126
            $friendId = $friendRelation->getFriend()->getId();
1127
            $relationThroughFriend = $em->getRepository(UserRelUser::class)
1128
                ->findOneBy([
1129
                    'relationType' => [
1130
                        UserRelUser::USER_RELATION_TYPE_FRIEND,
1131
                        UserRelUser::USER_RELATION_TYPE_GOODFRIEND,
1132
                    ],
1133
                    'friend' => $otherUserId,
1134
                    'user' => $friendId,
1135
                ])
1136
            ;
1137
1138
            if (null !== $relationThroughFriend) {
1139
                return true;
1140
            }
1141
        }
1142
1143
        return false;
1144
    }
1145
1146
    /**
1147
     * Checks the chat status of a user based on their user ID. It verifies if the user's chat status
1148
     * is active (indicated by a status of 1).
1149
     */
1150
    private function checkUserStatus(int $userId, UserRepository $userRepository): bool
1151
    {
1152
        $userStatus = $userRepository->getExtraUserDataByField($userId, 'user_chat_status');
1153
1154
        return !empty($userStatus) && isset($userStatus['user_chat_status']) && 1 === (int) $userStatus['user_chat_status'];
1155
    }
1156
1157
    /**
1158
     * Retrieves the most recent legal terms for a specified language. If no terms are found for the given language,
1159
     * the function attempts to retrieve terms for the platform's default language. If terms are still not found,
1160
     * it defaults to English ('en_US').
1161
     */
1162
    private function getLastConditionByLanguage(LanguageRepository $languageRepo, string $isoCode, LegalRepository $legalTermsRepo, SettingsManager $settingsManager): ?Legal
1163
    {
1164
        $language = $languageRepo->findByIsoCode($isoCode);
1165
        $languageId = (int) $language->getId();
1166
        $term = $legalTermsRepo->getLastConditionByLanguage($languageId);
1167
        if (!$term) {
1168
            $defaultLanguage = $settingsManager->getSetting('language.platform_language');
1169
            $language = $languageRepo->findByIsoCode($defaultLanguage);
1170
            $languageId = (int) $language->getId();
1171
            $term = $legalTermsRepo->getLastConditionByLanguage((int) $languageId);
1172
            if (!$term) {
1173
                $language = $languageRepo->findByIsoCode('en_US');
1174
                $languageId = (int) $language->getId();
1175
                $term = $legalTermsRepo->getLastConditionByLanguage((int) $languageId);
1176
            }
1177
        }
1178
1179
        return $term;
1180
    }
1181
}
1182