CourseChatUtils.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Chamilo\CoreBundle\Entity\Course;
  4. use Chamilo\CoreBundle\Entity\CourseRelUser;
  5. use Chamilo\CoreBundle\Entity\Session;
  6. use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
  7. use Chamilo\CourseBundle\Entity\CChatConnected;
  8. use Chamilo\UserBundle\Entity\User;
  9. use Doctrine\Common\Collections\Criteria;
  10. use Michelf\MarkdownExtra;
  11. /**
  12. * Class CourseChat
  13. * Manage the chat for a course.
  14. */
  15. class CourseChatUtils
  16. {
  17. private $groupId;
  18. private $courseId;
  19. private $sessionId;
  20. private $userId;
  21. /**
  22. * CourseChat constructor.
  23. *
  24. * @param int $courseId
  25. * @param int $userId
  26. * @param int $sessionId
  27. * @param int $groupId
  28. */
  29. public function __construct($courseId, $userId, $sessionId = 0, $groupId = 0)
  30. {
  31. $this->courseId = (int) $courseId;
  32. $this->userId = (int) $userId;
  33. $this->sessionId = (int) $sessionId;
  34. $this->groupId = (int) $groupId;
  35. }
  36. /**
  37. * Prepare a message. Clean and insert emojis.
  38. *
  39. * @param string $message The message to prepare
  40. *
  41. * @return string
  42. */
  43. public static function prepareMessage($message)
  44. {
  45. if (empty($message)) {
  46. return '';
  47. }
  48. Emojione\Emojione::$imagePathPNG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/png/';
  49. Emojione\Emojione::$ascii = true;
  50. $message = trim($message);
  51. $message = nl2br($message);
  52. // Security XSS
  53. $message = Security::remove_XSS($message);
  54. //search urls
  55. $message = preg_replace(
  56. '@((https?://)?([-\w]+\.[-\w\.]+)+\w(:\d+)?(/([-\w/_\.]*(\?\S+)?)?)*)@',
  57. '<a href="$1" target="_blank">$1</a>',
  58. $message
  59. );
  60. // add "http://" if not set
  61. $message = preg_replace(
  62. '/<a\s[^>]*href\s*=\s*"((?!https?:\/\/)[^"]*)"[^>]*>/i',
  63. '<a href="http://$1" target="_blank">',
  64. $message
  65. );
  66. // Parsing emojis
  67. $message = Emojione\Emojione::toImage($message);
  68. // Parsing text to understand markdown (code highlight)
  69. $message = MarkdownExtra::defaultTransform($message);
  70. return $message;
  71. }
  72. /**
  73. * Save a chat message in a HTML file.
  74. *
  75. * @param string $message
  76. * @param int $friendId
  77. *
  78. * @return bool
  79. */
  80. public function saveMessage($message, $friendId = 0)
  81. {
  82. if (empty($message)) {
  83. return false;
  84. }
  85. $friendId = (int) $friendId;
  86. $user = api_get_user_entity($this->userId);
  87. $courseInfo = api_get_course_info_by_id($this->courseId);
  88. $isMaster = api_is_course_admin();
  89. $document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
  90. $basepath_chat = '/chat_files';
  91. $group_info = [];
  92. if ($this->groupId) {
  93. $group_info = GroupManager::get_group_properties($this->groupId);
  94. $basepath_chat = $group_info['directory'].'/chat_files';
  95. }
  96. $chat_path = $document_path.$basepath_chat.'/';
  97. if (!is_dir($chat_path)) {
  98. if (is_file($chat_path)) {
  99. @unlink($chat_path);
  100. }
  101. }
  102. $date_now = date('Y-m-d');
  103. $timeNow = date('d/m/y H:i:s');
  104. $basename_chat = 'messages-'.$date_now;
  105. if ($this->groupId && !$friendId) {
  106. $basename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId;
  107. } elseif ($this->sessionId && !$friendId) {
  108. $basename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId;
  109. } elseif ($friendId) {
  110. if ($this->userId < $friendId) {
  111. $basename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId;
  112. } else {
  113. $basename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId;
  114. }
  115. }
  116. $message = self::prepareMessage($message);
  117. $fileTitle = $basename_chat.'.log.html';
  118. $filePath = $basepath_chat.'/'.$fileTitle;
  119. $absoluteFilePath = $chat_path.$fileTitle;
  120. if (!file_exists($absoluteFilePath)) {
  121. $doc_id = DocumentManager::addDocument(
  122. $courseInfo,
  123. $filePath,
  124. 'file',
  125. 0,
  126. $fileTitle,
  127. null,
  128. 0,
  129. true,
  130. 0,
  131. 0,
  132. 0,
  133. false
  134. );
  135. } else {
  136. $doc_id = DocumentManager::get_document_id($courseInfo, $filePath);
  137. }
  138. $fp = fopen($absoluteFilePath, 'a');
  139. $userPhoto = UserManager::getUserPicture($this->userId, USER_IMAGE_SIZE_MEDIUM);
  140. if ($isMaster) {
  141. $fileContent = '
  142. <div class="message-teacher">
  143. <div class="content-message">
  144. <div class="chat-message-block-name">'.UserManager::formatUserFullName($user).'</div>
  145. <div class="chat-message-block-content">'.$message.'</div>
  146. <div class="message-date">'.$timeNow.'</div>
  147. </div>
  148. <div class="icon-message"></div>
  149. <img class="chat-image" src="'.$userPhoto.'">
  150. </div>
  151. ';
  152. } else {
  153. $fileContent = '
  154. <div class="message-student">
  155. <img class="chat-image" src="'.$userPhoto.'">
  156. <div class="icon-message"></div>
  157. <div class="content-message">
  158. <div class="chat-message-block-name">'.UserManager::formatUserFullName($user).'</div>
  159. <div class="chat-message-block-content">'.$message.'</div>
  160. <div class="message-date">'.$timeNow.'</div>
  161. </div>
  162. </div>
  163. ';
  164. }
  165. fputs($fp, $fileContent);
  166. fclose($fp);
  167. $size = filesize($absoluteFilePath);
  168. update_existing_document($courseInfo, $doc_id, $size);
  169. item_property_update_on_folder($courseInfo, $basepath_chat, $this->userId);
  170. return true;
  171. }
  172. /**
  173. * Disconnect a user from course chats.
  174. *
  175. * @param int $userId
  176. */
  177. public static function exitChat($userId)
  178. {
  179. $listCourse = CourseManager::get_courses_list_by_user_id($userId);
  180. foreach ($listCourse as $course) {
  181. Database::getManager()
  182. ->createQuery('
  183. DELETE FROM ChamiloCourseBundle:CChatConnected ccc
  184. WHERE ccc.cId = :course AND ccc.userId = :user
  185. ')
  186. ->execute([
  187. 'course' => intval($course['real_id']),
  188. 'user' => intval($userId),
  189. ]);
  190. }
  191. }
  192. /**
  193. * Disconnect users who are more than 5 seconds inactive.
  194. */
  195. public function disconnectInactiveUsers()
  196. {
  197. $em = Database::getManager();
  198. $extraCondition = "AND ccc.toGroupId = {$this->groupId}";
  199. if (empty($this->groupId)) {
  200. $extraCondition = "AND ccc.sessionId = {$this->sessionId}";
  201. }
  202. $connectedUsers = $em
  203. ->createQuery("
  204. SELECT ccc FROM ChamiloCourseBundle:CChatConnected ccc
  205. WHERE ccc.cId = :course $extraCondition
  206. ")
  207. ->setParameter('course', $this->courseId)
  208. ->getResult();
  209. $now = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
  210. $cd_count_time_seconds = $now->getTimestamp();
  211. /** @var CChatConnected $connection */
  212. foreach ($connectedUsers as $connection) {
  213. $date_count_time_seconds = $connection->getLastConnection()->getTimestamp();
  214. if (strcmp($now->format('Y-m-d'), $connection->getLastConnection()->format('Y-m-d')) !== 0) {
  215. continue;
  216. }
  217. if (($cd_count_time_seconds - $date_count_time_seconds) <= 5) {
  218. continue;
  219. }
  220. $em
  221. ->createQuery('
  222. DELETE FROM ChamiloCourseBundle:CChatConnected ccc
  223. WHERE ccc.cId = :course AND ccc.userId = :user AND ccc.toGroupId = :group
  224. ')
  225. ->execute([
  226. 'course' => $this->courseId,
  227. 'user' => $connection->getUserId(),
  228. 'group' => $this->groupId,
  229. ]);
  230. }
  231. }
  232. /**
  233. * Keep registered to a user as connected.
  234. */
  235. public function keepUserAsConnected()
  236. {
  237. $em = Database::getManager();
  238. $extraCondition = null;
  239. if ($this->groupId) {
  240. $extraCondition = 'AND ccc.toGroupId = '.intval($this->groupId);
  241. } else {
  242. $extraCondition = 'AND ccc.sessionId = '.intval($this->sessionId);
  243. }
  244. $currentTime = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
  245. $connection = $em
  246. ->createQuery("
  247. SELECT ccc FROM ChamiloCourseBundle:CChatConnected ccc
  248. WHERE ccc.userId = :user AND ccc.cId = :course $extraCondition
  249. ")
  250. ->setParameters([
  251. 'user' => $this->userId,
  252. 'course' => $this->courseId,
  253. ])
  254. ->getOneOrNullResult();
  255. if ($connection) {
  256. $connection->setLastConnection($currentTime);
  257. $em->merge($connection);
  258. $em->flush();
  259. return;
  260. }
  261. $connection = new CChatConnected();
  262. $connection
  263. ->setCId($this->courseId)
  264. ->setUserId($this->userId)
  265. ->setLastConnection($currentTime)
  266. ->setSessionId($this->sessionId)
  267. ->setToGroupId($this->groupId);
  268. $em->persist($connection);
  269. $em->flush();
  270. }
  271. /**
  272. * Get the emoji allowed on course chat.
  273. *
  274. * @return array
  275. */
  276. public static function getEmojiStrategy()
  277. {
  278. return require_once api_get_path(SYS_CODE_PATH).'chat/emoji_strategy.php';
  279. }
  280. /**
  281. * Get the emoji list to include in chat.
  282. *
  283. * @return array
  284. */
  285. public static function getEmojisToInclude()
  286. {
  287. return [
  288. ':bowtie:',
  289. ':smile:' |
  290. ':laughing:',
  291. ':blush:',
  292. ':smiley:',
  293. ':relaxed:',
  294. ':smirk:',
  295. ':heart_eyes:',
  296. ':kissing_heart:',
  297. ':kissing_closed_eyes:',
  298. ':flushed:',
  299. ':relieved:',
  300. ':satisfied:',
  301. ':grin:',
  302. ':wink:',
  303. ':stuck_out_tongue_winking_eye:',
  304. ':stuck_out_tongue_closed_eyes:',
  305. ':grinning:',
  306. ':kissing:',
  307. ':kissing_smiling_eyes:',
  308. ':stuck_out_tongue:',
  309. ':sleeping:',
  310. ':worried:',
  311. ':frowning:',
  312. ':anguished:',
  313. ':open_mouth:',
  314. ':grimacing:',
  315. ':confused:',
  316. ':hushed:',
  317. ':expressionless:',
  318. ':unamused:',
  319. ':sweat_smile:',
  320. ':sweat:',
  321. ':disappointed_relieved:',
  322. ':weary:',
  323. ':pensive:',
  324. ':disappointed:',
  325. ':confounded:',
  326. ':fearful:',
  327. ':cold_sweat:',
  328. ':persevere:',
  329. ':cry:',
  330. ':sob:',
  331. ':joy:',
  332. ':astonished:',
  333. ':scream:',
  334. ':neckbeard:',
  335. ':tired_face:',
  336. ':angry:',
  337. ':rage:',
  338. ':triumph:',
  339. ':sleepy:',
  340. ':yum:',
  341. ':mask:',
  342. ':sunglasses:',
  343. ':dizzy_face:',
  344. ':imp:',
  345. ':smiling_imp:',
  346. ':neutral_face:',
  347. ':no_mouth:',
  348. ':innocent:',
  349. ':alien:',
  350. ];
  351. }
  352. /**
  353. * Get the chat history file name.
  354. *
  355. * @param bool $absolute Optional. Whether get the base or the absolute file path
  356. * @param int $friendId optional
  357. *
  358. * @return string
  359. */
  360. public function getFileName($absolute = false, $friendId = 0)
  361. {
  362. $date = date('Y-m-d');
  363. $base = 'messages-'.$date.'.log.html';
  364. if ($this->groupId && !$friendId) {
  365. $base = 'messages-'.$date.'_gid-'.$this->groupId.'.log.html';
  366. } elseif ($this->sessionId && !$friendId) {
  367. $base = 'messages-'.$date.'_sid-'.$this->sessionId.'.log.html';
  368. } elseif ($friendId) {
  369. if ($this->userId < $friendId) {
  370. $base = 'messages-'.$date.'_uid-'.$this->userId.'-'.$friendId.'.log.html';
  371. } else {
  372. $base = 'messages-'.$date.'_uid-'.$friendId.'-'.$this->userId.'.log.html';
  373. }
  374. }
  375. if (!$absolute) {
  376. return $base;
  377. }
  378. $courseInfo = api_get_course_info_by_id($this->courseId);
  379. $document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
  380. $chatPath = $document_path.'/chat_files/';
  381. if ($this->groupId) {
  382. $group_info = GroupManager::get_group_properties($this->groupId);
  383. $chatPath = $document_path.$group_info['directory'].'/chat_files/';
  384. }
  385. return $chatPath.$base;
  386. }
  387. /**
  388. * Get the chat history.
  389. *
  390. * @param bool $reset
  391. * @param int $friendId optional
  392. *
  393. * @return string
  394. */
  395. public function readMessages($reset = false, $friendId = 0)
  396. {
  397. $courseInfo = api_get_course_info_by_id($this->courseId);
  398. $date_now = date('Y-m-d');
  399. $isMaster = (bool) api_is_course_admin();
  400. $basepath_chat = '/chat_files';
  401. $document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
  402. $group_info = [];
  403. if ($this->groupId) {
  404. $group_info = GroupManager:: get_group_properties($this->groupId);
  405. $basepath_chat = $group_info['directory'].'/chat_files';
  406. }
  407. $chat_path = $document_path.$basepath_chat.'/';
  408. if (!is_dir($chat_path)) {
  409. if (is_file($chat_path)) {
  410. @unlink($chat_path);
  411. }
  412. if (!api_is_anonymous()) {
  413. @mkdir($chat_path, api_get_permissions_for_new_directories());
  414. // Save chat files document for group into item property
  415. if ($this->groupId) {
  416. DocumentManager::addDocument(
  417. $courseInfo,
  418. $basepath_chat,
  419. 'folder',
  420. 0,
  421. 'chat_files',
  422. null,
  423. 0,
  424. true,
  425. 0,
  426. 0,
  427. 0,
  428. false
  429. );
  430. }
  431. }
  432. }
  433. $filename_chat = 'messages-'.$date_now.'.log.html';
  434. if ($this->groupId && !$friendId) {
  435. $filename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId.'.log.html';
  436. } elseif ($this->sessionId && !$friendId) {
  437. $filename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId.'.log.html';
  438. } elseif ($friendId) {
  439. if ($this->userId < $friendId) {
  440. $filename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId.'.log.html';
  441. } else {
  442. $filename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId.'.log.html';
  443. }
  444. }
  445. if (!file_exists($chat_path.$filename_chat)) {
  446. @fclose(fopen($chat_path.$filename_chat, 'w'));
  447. if (!api_is_anonymous()) {
  448. DocumentManager::addDocument(
  449. $courseInfo,
  450. $basepath_chat.'/'.$filename_chat,
  451. 'file',
  452. 0,
  453. $filename_chat,
  454. null,
  455. 0,
  456. true,
  457. 0,
  458. 0,
  459. 0,
  460. false
  461. );
  462. }
  463. }
  464. $basename_chat = 'messages-'.$date_now;
  465. if ($this->groupId && !$friendId) {
  466. $basename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId;
  467. } elseif ($this->sessionId && !$friendId) {
  468. $basename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId;
  469. } elseif ($friendId) {
  470. if ($this->userId < $friendId) {
  471. $basename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId;
  472. } else {
  473. $basename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId;
  474. }
  475. }
  476. if ($reset && $isMaster) {
  477. $i = 1;
  478. while (file_exists($chat_path.$basename_chat.'-'.$i.'.log.html')) {
  479. $i++;
  480. }
  481. @rename($chat_path.$basename_chat.'.log.html', $chat_path.$basename_chat.'-'.$i.'.log.html');
  482. @fclose(fopen($chat_path.$basename_chat.'.log.html', 'w'));
  483. $doc_id = DocumentManager::addDocument(
  484. $courseInfo,
  485. $basepath_chat.'/'.$basename_chat.'-'.$i.'.log.html',
  486. 'file',
  487. filesize($chat_path.$basename_chat.'-'.$i.'.log.html'),
  488. $basename_chat.'-'.$i.'.log.html',
  489. null,
  490. 0,
  491. true,
  492. 0,
  493. 0,
  494. 0,
  495. false
  496. );
  497. $doc_id = DocumentManager::get_document_id(
  498. $courseInfo,
  499. $basepath_chat.'/'.$basename_chat.'.log.html'
  500. );
  501. update_existing_document($courseInfo, $doc_id, 0);
  502. }
  503. $remove = 0;
  504. $content = [];
  505. if (file_exists($chat_path.$basename_chat.'.log.html')) {
  506. $content = file($chat_path.$basename_chat.'.log.html');
  507. $nbr_lines = sizeof($content);
  508. $remove = $nbr_lines - 100;
  509. }
  510. if ($remove < 0) {
  511. $remove = 0;
  512. }
  513. array_splice($content, 0, $remove);
  514. if (isset($_GET['origin']) && $_GET['origin'] == 'whoisonline') {
  515. //the caller
  516. $content[0] = get_lang('Chat call has been sent. Waiting for the approval of your partner.').'<br />'.$content[0];
  517. }
  518. $history = '<div id="content-chat">';
  519. foreach ($content as $this_line) {
  520. $history .= $this_line;
  521. }
  522. $history .= '</div>';
  523. if ($isMaster || $GLOBALS['is_session_general_coach']) {
  524. $history .= '
  525. <div id="clear-chat">
  526. <button type="button" id="chat-reset" class="btn btn-danger btn-sm">
  527. '.get_lang('Clear the chat').'
  528. </button>
  529. </div>
  530. ';
  531. }
  532. return $history;
  533. }
  534. /**
  535. * Get the number of users connected in chat.
  536. *
  537. * @return int
  538. */
  539. public function countUsersOnline()
  540. {
  541. $date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
  542. $date->modify('-5 seconds');
  543. if ($this->groupId) {
  544. $extraCondition = 'AND ccc.toGroupId = '.intval($this->groupId);
  545. } else {
  546. $extraCondition = 'AND ccc.sessionId = '.intval($this->sessionId);
  547. }
  548. $number = Database::getManager()
  549. ->createQuery("
  550. SELECT COUNT(ccc.userId) FROM ChamiloCourseBundle:CChatConnected ccc
  551. WHERE ccc.lastConnection > :date AND ccc.cId = :course $extraCondition
  552. ")
  553. ->setParameters([
  554. 'date' => $date,
  555. 'course' => $this->courseId,
  556. ])
  557. ->getSingleScalarResult();
  558. return (int) $number;
  559. }
  560. /**
  561. * Get the users online data.
  562. *
  563. * @throws \Doctrine\ORM\ORMException
  564. * @throws \Doctrine\ORM\OptimisticLockException
  565. * @throws \Doctrine\ORM\TransactionRequiredException
  566. *
  567. * @return array
  568. */
  569. public function listUsersOnline()
  570. {
  571. $subscriptions = $this->getUsersSubscriptions();
  572. $usersInfo = [];
  573. if ($this->groupId) {
  574. /** @var User $groupUser */
  575. foreach ($subscriptions as $groupUser) {
  576. $usersInfo[] = $this->formatUser(
  577. $groupUser,
  578. $groupUser->getStatus()
  579. );
  580. }
  581. } else {
  582. /** @var CourseRelUser|SessionRelCourseRelUser $subscription */
  583. foreach ($subscriptions as $subscription) {
  584. $user = $subscription->getUser();
  585. $usersInfo[] = $this->formatUser(
  586. $user,
  587. $this->sessionId ? $user->getStatus() : $subscription->getStatus()
  588. );
  589. }
  590. }
  591. return $usersInfo;
  592. }
  593. /**
  594. * Format the user data to return it in the user list.
  595. *
  596. * @param User $user
  597. * @param int $status
  598. *
  599. * @return array
  600. */
  601. private function formatUser(User $user, $status)
  602. {
  603. return [
  604. 'id' => $user->getId(),
  605. 'firstname' => $user->getFirstname(),
  606. 'lastname' => $user->getLastname(),
  607. 'status' => $status,
  608. 'image_url' => UserManager::getUserPicture($user->getId(), USER_IMAGE_SIZE_MEDIUM),
  609. 'profile_url' => api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user->getId(),
  610. 'complete_name' => UserManager::formatUserFullName($user),
  611. 'username' => $user->getUsername(),
  612. 'email' => $user->getEmail(),
  613. 'isConnected' => $this->userIsConnected($user->getId()),
  614. ];
  615. }
  616. /**
  617. * Get the users subscriptions (SessionRelCourseRelUser array or CourseRelUser array) for chat.
  618. *
  619. * @throws \Doctrine\ORM\ORMException
  620. * @throws \Doctrine\ORM\OptimisticLockException
  621. * @throws \Doctrine\ORM\TransactionRequiredException
  622. *
  623. * @return \Doctrine\Common\Collections\ArrayCollection
  624. */
  625. private function getUsersSubscriptions()
  626. {
  627. $em = Database::getManager();
  628. if ($this->groupId) {
  629. $students = $em
  630. ->createQuery(
  631. 'SELECT u FROM ChamiloUserBundle:User u
  632. INNER JOIN ChamiloCourseBundle:CGroupRelUser gru
  633. WITH u.id = gru.userId AND gru.cId = :course
  634. WHERE u.id != :user AND gru.groupId = :group
  635. AND u.active = true'
  636. )
  637. ->setParameters(['course' => $this->courseId, 'user' => $this->userId, 'group' => $this->groupId])
  638. ->getResult();
  639. $tutors = $em
  640. ->createQuery(
  641. 'SELECT u FROM ChamiloUserBundle:User u
  642. INNER JOIN ChamiloCourseBundle:CGroupRelTutor grt
  643. WITH u.id = grt.userId AND grt.cId = :course
  644. WHERE u.id != :user AND grt.groupId = :group
  645. AND u.active = true'
  646. )
  647. ->setParameters(['course' => $this->courseId, 'user' => $this->userId, 'group' => $this->groupId])
  648. ->getResult();
  649. return array_merge($tutors, $students);
  650. }
  651. /** @var Course $course */
  652. $course = $em->find('ChamiloCoreBundle:Course', $this->courseId);
  653. if ($this->sessionId) {
  654. /** @var Session $session */
  655. $session = $em->find('ChamiloCoreBundle:Session', $this->sessionId);
  656. $criteria = Criteria::create()->where(Criteria::expr()->eq('course', $course));
  657. $userIsCoach = api_is_course_session_coach($this->userId, $course->getId(), $session->getId());
  658. if (api_get_configuration_value('course_chat_restrict_to_coach')) {
  659. if ($userIsCoach) {
  660. $criteria->andWhere(
  661. Criteria::expr()->eq('status', Session::STUDENT)
  662. );
  663. } else {
  664. $criteria->andWhere(
  665. Criteria::expr()->eq('status', Session::COACH)
  666. );
  667. }
  668. }
  669. $criteria->orderBy(['status' => Criteria::DESC]);
  670. return $session
  671. ->getUserCourseSubscriptions()
  672. ->matching($criteria)
  673. ->filter(function (SessionRelCourseRelUser $sessionRelCourseRelUser) {
  674. return $sessionRelCourseRelUser->getUser()->isActive();
  675. });
  676. }
  677. return $course
  678. ->getUsers()
  679. ->filter(function (CourseRelUser $courseRelUser) {
  680. return $courseRelUser->getUser()->isActive();
  681. });
  682. }
  683. /**
  684. * Check if a user is connected in course chat.
  685. *
  686. * @param int $userId
  687. *
  688. * @return int
  689. */
  690. private function userIsConnected($userId)
  691. {
  692. $date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
  693. $date->modify('-5 seconds');
  694. if ($this->groupId) {
  695. $extraCondition = 'AND ccc.toGroupId = '.intval($this->groupId);
  696. } else {
  697. $extraCondition = 'AND ccc.sessionId = '.intval($this->sessionId);
  698. }
  699. $number = Database::getManager()
  700. ->createQuery("
  701. SELECT COUNT(ccc.userId) FROM ChamiloCourseBundle:CChatConnected ccc
  702. WHERE ccc.lastConnection > :date AND ccc.cId = :course AND ccc.userId = :user $extraCondition
  703. ")
  704. ->setParameters([
  705. 'date' => $date,
  706. 'course' => $this->courseId,
  707. 'user' => $userId,
  708. ])
  709. ->getSingleScalarResult();
  710. return (int) $number;
  711. }
  712. }