SocialController::getUserProfile()   B
last analyzed

Complexity

Conditions 7
Paths 25

Size

Total Lines 52
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 30
c 1
b 0
f 0
nc 25
nop 8
dl 0
loc 52
rs 8.5066

How to fix   Long Method    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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