2626use Chamilo \CoreBundle \Repository \Node \UsergroupRepository ;
2727use Chamilo \CoreBundle \Repository \Node \UserRepository ;
2828use Chamilo \CoreBundle \Repository \TrackEOnlineRepository ;
29+ use Chamilo \CoreBundle \Security \Authorization \Voter \UserVoter ;
2930use Chamilo \CoreBundle \Serializer \UserToJsonNormalizer ;
3031use Chamilo \CoreBundle \Settings \SettingsManager ;
3132use Chamilo \CourseBundle \Repository \CForumThreadRepository ;
4950use Symfony \Contracts \Translation \TranslatorInterface ;
5051use UserManager ;
5152
53+ #[IsGranted('ROLE_USER ' )]
5254#[Route('/social-network ' )]
5355class SocialController extends AbstractController
5456{
@@ -178,8 +180,7 @@ public function getLegalTerms(
178180 #[Route('/legal-status/{userId} ' , name: 'chamilo_core_social_legal_status ' )]
179181 public function getLegalStatus (
180182 int $ userId ,
181- #[CurrentUser]
182- User $ currentUser ,
183+ #[CurrentUser] User $ currentUser ,
183184 SettingsManager $ settingsManager ,
184185 TranslatorInterface $ translator ,
185186 UserRepository $ userRepo ,
@@ -204,8 +205,17 @@ public function getLegalStatus(
204205 }
205206
206207 $ isoCode = $ currentUser ->getLocale ();
207- $ latestLanguageId = $ this ->resolveLegalLanguageId ($ languageRepo , $ isoCode , $ settingsManager );
208- $ latestVersion = 0 !== $ latestLanguageId ? $ legalTermsRepo ->getLastVersionByLanguage ($ latestLanguageId ) : null ;
208+
209+ $ resolved = $ this ->resolveLatestTermsVersion ($ isoCode , $ languageRepo , $ legalTermsRepo , $ settingsManager );
210+ if (!$ resolved ) {
211+ return $ this ->json ([
212+ 'isAccepted ' => false ,
213+ 'message ' => $ translator ->trans ('No terms and conditions available ' , [], 'messages ' ),
214+ ], Response::HTTP_NOT_FOUND );
215+ }
216+
217+ $ latestLanguageId = (int ) $ resolved ['languageId ' ];
218+ $ latestVersion = (int ) $ resolved ['version ' ];
209219
210220 $ extraFieldValue = new ExtraFieldValue ('user ' );
211221 $ value = $ extraFieldValue ->get_values_by_handler_and_field_variable ($ userId , 'legal_accept ' );
@@ -239,46 +249,59 @@ public function getLegalStatus(
239249 ]);
240250 }
241251
242- #[Route('/send-legal-term ' , name: 'chamilo_core_social_send_legal_term ' )]
252+ #[Route('/send-legal-term ' , name: 'chamilo_core_social_send_legal_term ' , methods: [ ' POST ' ] )]
243253 public function sendLegalTerm (
244254 Request $ request ,
255+ #[CurrentUser] User $ currentUser ,
245256 SettingsManager $ settingsManager ,
246257 TranslatorInterface $ translator ,
247258 LegalRepository $ legalTermsRepo ,
248259 UserRepository $ userRepo ,
249260 LanguageRepository $ languageRepo
250261 ): JsonResponse {
251262 $ data = json_decode ($ request ->getContent (), true );
252- $ userId = $ data ['userId ' ] ?? null ;
253-
254- $ user = $ userRepo ->find ($ userId );
255- if (!$ user ) {
256- return $ this ->json (['error ' => 'User not found ' ], Response::HTTP_NOT_FOUND );
263+ if (!is_array ($ data )) {
264+ return $ this ->json (['error ' => 'Invalid JSON body ' ], Response::HTTP_BAD_REQUEST );
257265 }
258266
259- $ isoCode = $ user ->getLocale ();
260- $ languageId = $ this ->resolveLegalLanguageId ($ languageRepo , $ isoCode , $ settingsManager );
261- if (0 === $ languageId ) {
262- return $ this ->json (['error ' => 'Language not found ' ], Response::HTTP_BAD_REQUEST );
267+ $ requestedUserId = isset ($ data ['userId ' ]) ? (int ) $ data ['userId ' ] : 0 ;
268+
269+ // Non-admin users can only accept terms for themselves.
270+ if (!$ this ->isGranted ('ROLE_ADMIN ' )) {
271+ $ targetUserId = $ currentUser ->getId ();
272+ $ user = $ currentUser ;
273+ } else {
274+ $ targetUserId = $ requestedUserId > 0 ? $ requestedUserId : 0 ;
275+ if (0 === $ targetUserId ) {
276+ return $ this ->json (['error ' => 'Missing or invalid userId ' ], Response::HTTP_BAD_REQUEST );
277+ }
278+ $ user = $ userRepo ->find ($ targetUserId );
279+ if (!$ user ) {
280+ return $ this ->json (['error ' => 'User not found ' ], Response::HTTP_NOT_FOUND );
281+ }
263282 }
264283
265- $ version = $ legalTermsRepo ->getLastVersionByLanguage ($ languageId );
266- if (null === $ version ) {
284+ $ isoCode = $ user ->getLocale ();
285+ $ resolved = $ this ->resolveLatestTermsVersion ($ isoCode , $ languageRepo , $ legalTermsRepo , $ settingsManager );
286+ if (!$ resolved ) {
267287 return $ this ->json (['error ' => 'Terms not found ' ], Response::HTTP_NOT_FOUND );
268288 }
289+ $ languageId = (int ) $ resolved ['languageId ' ];
290+ $ version = (int ) $ resolved ['version ' ];
269291
270- $ legalAcceptType = $ version. ': ' . $ languageId. ': ' . time ();
271- UserManager::update_extra_field_value (( int ) $ userId , 'legal_accept ' , $ legalAcceptType );
292+ $ legalAcceptType = $ version . ': ' . $ languageId . ': ' . time ();
293+ UserManager::update_extra_field_value ($ targetUserId , 'legal_accept ' , $ legalAcceptType );
272294
273- $ bossList = UserManager::getStudentBossList ((int ) $ userId );
295+ // Notify bosses (kept as-is, now based on $targetUserId)
296+ $ bossList = UserManager::getStudentBossList ($ targetUserId );
274297 if (!empty ($ bossList )) {
275298 $ bossList = array_column ($ bossList , 'boss_id ' );
276299 foreach ($ bossList as $ bossId ) {
277- $ subjectEmail = \ sprintf (
300+ $ subjectEmail = sprintf (
278301 $ translator ->trans ('User %s signed the agreement. ' , [], 'messages ' ),
279302 $ user ->getFullName ()
280303 );
281- $ contentEmail = \ sprintf (
304+ $ contentEmail = sprintf (
282305 $ translator ->trans ('User %s signed the agreement the %s. ' , [], 'messages ' ),
283306 $ user ->getFullName (),
284307 $ this ->dateTimeHelper ->localTimeYmdHis (null , null , 'UTC ' )
@@ -288,7 +311,7 @@ public function sendLegalTerm(
288311 (int ) $ bossId ,
289312 $ subjectEmail ,
290313 $ contentEmail ,
291- ( int ) $ userId
314+ $ targetUserId
292315 );
293316 }
294317 }
@@ -299,88 +322,123 @@ public function sendLegalTerm(
299322 ]);
300323 }
301324
302- #[IsGranted('ROLE_ADMIN ' )]
303- #[Route('/delete-legal ' , name: 'chamilo_core_social_delete_legal ' )]
325+ #[Route('/delete-legal ' , name: 'chamilo_core_social_delete_legal ' , methods: ['POST ' ])]
304326 public function deleteLegal (
305- #[CurrentUser]
306- User $ currentUser ,
327+ #[CurrentUser] User $ currentUser ,
307328 Request $ request ,
308329 TranslatorInterface $ translator
309330 ): JsonResponse {
310331 $ data = json_decode ($ request ->getContent (), true );
311- $ userId = $ data ['userId ' ] ?? null ;
332+ if (!is_array ($ data )) {
333+ return $ this ->json (['error ' => 'Invalid JSON body ' ], Response::HTTP_BAD_REQUEST );
334+ }
312335
313- if ($ userId !== $ currentUser ->getId ()) {
314- throw $ this ->createAccessDeniedException ();
336+ // Backward compatible: if userId is not provided, default to current user.
337+ $ requestedUserId = isset ($ data ['userId ' ]) ? (int ) $ data ['userId ' ] : 0 ;
338+
339+ // Non-admin users can only revoke their own consent (ignore provided userId if different).
340+ if (!$ this ->isGranted ('ROLE_ADMIN ' )) {
341+ $ targetUserId = $ currentUser ->getId ();
342+ } else {
343+ // Admin must explicitly provide a valid userId.
344+ $ targetUserId = $ requestedUserId > 0 ? $ requestedUserId : 0 ;
345+ if (0 === $ targetUserId ) {
346+ return $ this ->json (['error ' => 'Missing or invalid userId ' ], Response::HTTP_BAD_REQUEST );
347+ }
315348 }
316349
317350 $ extraFieldValue = new ExtraFieldValue ('user ' );
318- $ value = $ extraFieldValue ->get_values_by_handler_and_field_variable ($ userId , 'legal_accept ' );
319- if ($ value && isset ($ value ['id ' ])) {
351+
352+ $ value = $ extraFieldValue ->get_values_by_handler_and_field_variable ($ targetUserId , 'legal_accept ' );
353+ if (!empty ($ value ['id ' ])) {
320354 $ extraFieldValue ->delete ($ value ['id ' ]);
321355 }
322356
323- $ value = $ extraFieldValue ->get_values_by_handler_and_field_variable ($ userId , 'termactivated ' );
324- if ($ value && isset ($ value ['id ' ])) {
357+ $ value = $ extraFieldValue ->get_values_by_handler_and_field_variable ($ targetUserId , 'termactivated ' );
358+ if (! empty ($ value ['id ' ])) {
325359 $ extraFieldValue ->delete ($ value ['id ' ]);
326360 }
327361
328- return $ this ->json (['success ' => true , 'message ' => $ translator ->trans ('Legal consent revoked successfully. ' )]);
362+ return $ this ->json ([
363+ 'success ' => true ,
364+ 'message ' => $ translator ->trans ('Legal consent revoked successfully. ' ),
365+ ]);
329366 }
330367
331- #[Route('/handle-privacy-request ' , name: 'chamilo_core_social_handle_privacy_request ' )]
368+ #[Route('/handle-privacy-request ' , name: 'chamilo_core_social_handle_privacy_request ' , methods: [ ' POST ' ] )]
332369 public function handlePrivacyRequest (
333370 Request $ request ,
371+ #[CurrentUser] User $ currentUser ,
334372 SettingsManager $ settingsManager ,
335373 UserRepository $ userRepo ,
336374 TranslatorInterface $ translator ,
337- MailerInterface $ mailer ,
338- RequestStack $ requestStack
375+ MailerInterface $ mailer
339376 ): JsonResponse {
340377 $ data = json_decode ($ request ->getContent (), true );
341- $ userId = $ data[ ' userId ' ] ? ( int ) $ data [ ' userId ' ] : null ;
342- $ explanation = $ data [ ' explanation ' ] ?? '' ;
343- $ requestType = $ data [ ' requestType ' ] ?? '' ;
378+ if (! is_array ( $ data)) {
379+ return $ this -> json ([ ' success ' => false , ' message ' => ' Invalid JSON body ' ], Response:: HTTP_BAD_REQUEST ) ;
380+ }
344381
345- /** @var User $user */
346- $ user = $ userRepo ->find ($ userId );
382+ $ requestedUserId = isset ($ data ['userId ' ]) ? (int ) $ data ['userId ' ] : 0 ;
383+ $ explanation = (string ) ($ data ['explanation ' ] ?? '' );
384+ $ requestType = (string ) ($ data ['requestType ' ] ?? '' );
347385
348- if (!$ user ) {
349- return $ this ->json (['success ' => false , 'message ' => 'User not found ' ]);
386+ // Non-admin users can only create requests for themselves
387+ if (!$ this ->isGranted ('ROLE_ADMIN ' )) {
388+ $ targetUserId = $ currentUser ->getId ();
389+ $ user = $ currentUser ;
390+ } else {
391+ // Admin can create requests for another user if explicitly provided
392+ $ targetUserId = $ requestedUserId > 0 ? $ requestedUserId : 0 ;
393+ if (0 === $ targetUserId ) {
394+ return $ this ->json (['success ' => false , 'message ' => 'Missing or invalid userId ' ], Response::HTTP_BAD_REQUEST );
395+ }
396+ $ user = $ userRepo ->find ($ targetUserId );
397+ if (!$ user ) {
398+ return $ this ->json (['success ' => false , 'message ' => 'User not found ' ], Response::HTTP_NOT_FOUND );
399+ }
350400 }
351401
352- $ request = $ requestStack ->getCurrentRequest ();
353- $ baseUrl = $ request ->getSchemeAndHttpHost ().$ request ->getBasePath ();
354- $ specificPath = '/main/admin/user_list_consent.php ' ;
355- $ link = $ baseUrl .$ specificPath ;
402+ $ baseUrl = $ request ->getSchemeAndHttpHost () . $ request ->getBasePath ();
403+ $ link = $ baseUrl . '/main/admin/user_list_consent.php ' ;
356404
357405 if ('delete_account ' === $ requestType ) {
358406 $ fieldToUpdate = 'request_for_delete_account ' ;
359407 $ justificationFieldToUpdate = 'request_for_delete_account_justification ' ;
360408 $ emailSubject = $ translator ->trans ('Request for account removal ' );
361- $ 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> ' );
409+ $ emailContent = sprintf (
410+ $ translator ->trans ('User %s asked for the deletion of his/her account, explaining that "%s". You can process the request here: %s ' ),
411+ $ user ->getFullName (),
412+ $ explanation ,
413+ '<a href=" ' .$ link .'"> ' .$ link .'</a> '
414+ );
362415 } elseif ('delete_legal ' === $ requestType ) {
363416 $ fieldToUpdate = 'request_for_legal_agreement_consent_removal ' ;
364417 $ justificationFieldToUpdate = 'request_for_legal_agreement_consent_removal_justification ' ;
365418 $ emailSubject = $ translator ->trans ('Request for consent withdrawal on legal terms ' );
366- $ 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> ' );
419+ $ emailContent = sprintf (
420+ $ 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 ' ),
421+ $ user ->getFullName (),
422+ $ explanation ,
423+ '<a href=" ' .$ link .'"> ' .$ link .'</a> '
424+ );
367425 } else {
368- return $ this ->json (['success ' => false , 'message ' => 'Invalid action type ' ]);
426+ return $ this ->json (['success ' => false , 'message ' => 'Invalid action type ' ], Response:: HTTP_BAD_REQUEST );
369427 }
370428
371429 UserManager::createDataPrivacyExtraFields ();
372- UserManager::update_extra_field_value ($ userId , $ fieldToUpdate , 1 );
373- UserManager::update_extra_field_value ($ userId , $ justificationFieldToUpdate , $ explanation );
430+ UserManager::update_extra_field_value ($ targetUserId , $ fieldToUpdate , 1 );
431+ UserManager::update_extra_field_value ($ targetUserId , $ justificationFieldToUpdate , $ explanation );
432+
433+ $ emailOfficer = (string ) $ settingsManager ->getSetting ('profile.data_protection_officer_email ' );
374434
375- $ emailOfficer = $ settingsManager ->getSetting ('profile.data_protection_officer_email ' );
376- if (!empty ($ emailOfficer )) {
377- $ email = new Email ();
378- $ email
435+ if ('' !== trim ($ emailOfficer )) {
436+ $ email = (new Email ())
379437 ->from ($ user ->getEmail ())
380438 ->to ($ emailOfficer )
381439 ->subject ($ emailSubject )
382- ->html ($ emailContent )
383- ;
440+ ->html ($ emailContent );
441+
384442 $ mailer ->send ($ email );
385443 } else {
386444 MessageManager::sendMessageToAllAdminUsers ($ user ->getId (), $ emailSubject , $ emailContent );
@@ -529,7 +587,6 @@ public function groupInvitedUsers(int $groupId, UsergroupRepository $usergroupRe
529587 return $ this ->json (['invitedUsers ' => $ invitedUsersList ]);
530588 }
531589
532- #[IsGranted('ROLE_USER ' )]
533590 #[Route('/user-profile/{userId} ' , name: 'chamilo_core_social_user_profile ' )]
534591 public function getUserProfile (
535592 int $ userId ,
0 commit comments