Passed
Push — master ( 7f4fc5...0155f0 )
by
unknown
16:02 queued 08:04
created

SocialController::getUserProfile()   B

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