PageRenderTime 80ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/mess.php

https://github.com/blakeparkinson/dumbgame
PHP | 4102 lines | 3193 code | 407 blank | 502 comment | 1102 complexity | a0dc3cca20036ba39a066f4ec41c4dde MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * @category Edmodo
  5. * @package Edmodo_Helper
  6. * @copyright Copyright (c) 2012 Edmodo USA Inc. (http://www.edmodo.com)
  7. *
  8. */
  9. /**
  10. *
  11. * @category Edmodo
  12. * @package Edmodo_Helper
  13. *
  14. */
  15. class MessagingHelper
  16. {
  17. const MESSAGE='message';
  18. const MESSAGE_ID='message_id';
  19. const CREATOR_ID='creator_id';
  20. const TYPE='type';
  21. const CREATION_DATE='creation_date';
  22. const COLUMN_PUBLIC='public';
  23. const MESSAGE_TYPE_TEXT='text';
  24. const MESSAGE_TYPE_LINK='link';
  25. const MESSAGE_TYPE_VIDEO='video';
  26. const MESSAGE_TYPE_FILE='file';
  27. const MESSAGE_TYPE_ASSIGNMENT='assignment';
  28. const MESSAGE_TYPE_SYSTEM='system';
  29. const MESSAGE_TYPE_COMMENT='comment';
  30. const MESSAGE_TYPE_ALERT='alert';
  31. const MESSAGE_TYPE_GRADE='grade';
  32. const MESSAGE_TYPE_POLL='poll';
  33. const MESSAGE_TYPE_FEED='feed';
  34. const MESSAGE_TYPE_EMBED='embed';
  35. const MESSAGE_TYPE_QUIZ='quiz';
  36. const MESSAGE_TYPE_APP_MESSAGE='app_message';
  37. public static $VALID_MESSAGE_TYPES = array(
  38. MessagingHelper::MESSAGE_TYPE_TEXT,
  39. MessagingHelper::MESSAGE_TYPE_LINK,
  40. MessagingHelper::MESSAGE_TYPE_VIDEO,
  41. MessagingHelper::MESSAGE_TYPE_FILE,
  42. MessagingHelper::MESSAGE_TYPE_ASSIGNMENT,
  43. MessagingHelper::MESSAGE_TYPE_SYSTEM,
  44. MessagingHelper::MESSAGE_TYPE_COMMENT,
  45. MessagingHelper::MESSAGE_TYPE_ALERT,
  46. MessagingHelper::MESSAGE_TYPE_GRADE,
  47. MessagingHelper::MESSAGE_TYPE_POLL,
  48. MessagingHelper::MESSAGE_TYPE_FEED,
  49. MessagingHelper::MESSAGE_TYPE_EMBED,
  50. MessagingHelper::MESSAGE_TYPE_QUIZ,
  51. MessagingHelper::MESSAGE_TYPE_APP_MESSAGE,
  52. );
  53. private $use_gearman = NOTIFICATIONS_USE_GEARMAN;
  54. private $last_direct_msg_receivers;
  55. private $last_indirect_msg_receivers;
  56. private $spotted_replies;
  57. private $feed_type;
  58. private $user_id;
  59. private $user_groups;
  60. private $community_groups;
  61. private $parent_info;
  62. private $institutional_info;
  63. private static $layout_translator;
  64. private static $system_msgs_translator;
  65. public $post_limit_reached = false;
  66. public static $is_api_call = false;
  67. public static $limit_comments_query = true;
  68. /**
  69. *
  70. * @var MessagingHelper
  71. */
  72. private static $_instance;
  73. /**
  74. * Implements the "singleton" pattern for this class
  75. *
  76. * @param string $feed_type
  77. * @return MessagingHelper
  78. */
  79. static function getInstance ($feed_type = 'HOME_FEED')
  80. {
  81. if (! isset(self::$_instance)) {
  82. self::$_instance = new self($feed_type);
  83. } else {
  84. self::$_instance->setFeedType($feed_type);
  85. }
  86. return self::$_instance;
  87. }
  88. /**
  89. * Set class instance
  90. * Use only to mock/stub instance for tests
  91. *
  92. * @param MessagingHelper $instance
  93. * @throws Exception
  94. */
  95. static function setInstance ($instance)
  96. {
  97. if (! $instance instanceof MessagingHelper) {
  98. throw new Exception('Invalid instance class');
  99. }
  100. self::$_instance = $instance;
  101. }
  102. /**
  103. */
  104. static function clearInstance ()
  105. {
  106. self::$_instance = null;
  107. }
  108. private function __construct($feed_type = 'HOME_FEED')
  109. {
  110. //----------------------------
  111. // Stores the user_ids of the users who received the msg
  112. // directly (people typed their names in the sharebox)
  113. $this->last_direct_msg_receivers = array();
  114. //----------------------------
  115. // Stores the user_ids of the users who received the msg
  116. // indirectly (they are part of a group who received a post)
  117. $this->last_indirect_msg_receivers = array();
  118. //----------------------------
  119. // Stores a boolean map of the comments that have been already spotted by the user
  120. $this->spotted_replies = array();
  121. //----------------------------
  122. // Stores a boolean map of the comments that have been already spotted by the user
  123. $this->feed_type = $feed_type;
  124. //----------------------------
  125. // Stores id of the user of the feed we are looking at
  126. $this->viewed_user_id = 0;
  127. //----------------------------
  128. // Stores the status of the user with respect to the community stream being viewed
  129. $this->community_user_status = null;
  130. //----------------------------
  131. // Stores the groups that the user whose feed we are looking at is part of
  132. $this->viewed_user_groups = array();
  133. //----------------------------
  134. // Stores the groups that are being viewed as a receiver on the community page
  135. $this->community_groups = array();
  136. //----------------------------
  137. // Stores the schools/districts that the user whose feed we are looking at is part of
  138. $this->institutional_info = array();
  139. //Stores the parent's info about his students
  140. $this->parent_info = array();
  141. //----------------------------
  142. // Layout translator
  143. self::$layout_translator = null;
  144. //----------------------------
  145. // System messages translator
  146. self::$system_msgs_translator = null;
  147. }
  148. public function setFeedType($feed_type = 'HOME_FEED')
  149. {
  150. $this->feed_type = $feed_type;
  151. }
  152. public static function initializeTranslators($language){
  153. if(!isset(self::$layout_translator)){
  154. // self::$layout_translator = new TranslationHelper(new Zend_Translate('tmx', PATH2_LANGUAGES . 'layout.tmx', $language));
  155. self::$layout_translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'layout.tmx', $language);
  156. }
  157. if(!isset(self::$system_msgs_translator)){
  158. // self::$system_msgs_translator = new TranslationHelper(new Zend_Translate('tmx', PATH2_LANGUAGES . 'system.tmx', $language));
  159. self::$system_msgs_translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'system.tmx', $language);
  160. }
  161. }
  162. /**
  163. * This sends a message from the system to a user
  164. * @param string $message_identifier is the system message identifier
  165. * @param array $receiver_id is the id of the intended message recipient
  166. */
  167. public function sendSystemMessage($message_identifier, $receiver_ids = array()){
  168. $message_data = array(
  169. 'type' => 'system',
  170. 'message' => $message_identifier
  171. );
  172. $this->sendMessage(
  173. $message_data,
  174. array('people' => $receiver_ids),
  175. Users::getInstance()->getUserInfo(EDMODO_SYSTEM_USER_ID)
  176. );
  177. }
  178. /**
  179. * This sends a message to one or more peers
  180. * @param array $message_data contains the message's content plus additional info about the message
  181. * @param array $receivers contains the intended message recipients (people or locations or both)
  182. * @param array $sender_info is the sender's account info.
  183. * @param Boolean $resource_resending weather this message is being sent to resend a resource (eg from the Library).
  184. * @param $attached_resources
  185. * @param bool $check_send_rights, flag to indicate if a check should be performed to verify that the sender has rights to send the message
  186. * @param bool $use_response_obj_return, flag to indicate if a HandlerResponseObj should be returned instead of the normal returns
  187. * @param bool $bypass_moderation, flag to indicate if the message should be sent even if the poster is a student and one of the recipients a moderated group
  188. * @return message_id
  189. */
  190. public function sendMessage($message_data, $receivers, $sender_info, $resource_resending = FALSE, $attached_resources = '', $check_send_rights = true, $use_response_obj_return = false, $bypass_moderation = false )
  191. {
  192. $response_obj = new HandlerResponseObj();
  193. if($this->isSpammer($sender_info, $message_data)){
  194. if($use_response_obj_return){
  195. $response_obj->setUnsuccessful();
  196. $response_obj->post_limit_reached = true;
  197. $response_obj->addError('User has reached maximum limit of posts for the last hour');
  198. return $response_obj;
  199. }else{
  200. return false;
  201. }
  202. }
  203. if($check_send_rights){
  204. if ( $sender_info['user_id'] != EDMODO_SYSTEM_USER_ID && !$this->userHasRightsToSendMessage( $sender_info, $receivers, $message_data ))
  205. {
  206. if ($use_response_obj_return) {
  207. $response_obj->setUnsuccessful();
  208. $response_obj->addError('User does not have rights to send message to the specified recipients');
  209. return $response_obj;
  210. } else {
  211. return false;
  212. }
  213. }
  214. }
  215. $community_id=null;
  216. // Messages are only sent immediately if none of the recipients is a moderated group
  217. if ( !$bypass_moderation && !empty($receivers['locations']) ){
  218. $groups_db = Groups::getInstance();
  219. foreach ( $receivers['locations'] as $location ){
  220. if ( $location['type'] == 'group' ){
  221. $group = $groups_db->find($location['id'])->current();
  222. // For small groups, the parent group is checked for moderation
  223. $main_group_info = SmallGroups::getInstance()->getGroupsMainGroup($location['id']);
  224. if ( empty($main_group_info) ){
  225. $main_group_info = $group;
  226. }
  227. if ( $main_group_info['moderated'] && ( $sender_info['type'] == 'STUDENT' || !$groups_db->userOwnsGroup( $sender_info['user_id'], $main_group_info['group_id'], true )) ){
  228. // Post moderated message here
  229. ModeratedMessagesHandler::sendModeratedMessage($message_data, $attached_resources, $group, $sender_info);
  230. if ($use_response_obj_return) {
  231. $response_obj->setSuccessful();
  232. $response_obj->is_moderated = true;
  233. $response_obj->message_id = 0;
  234. $response_obj->scheduled_message_id = 0;
  235. return $response_obj;
  236. } else {
  237. return false;
  238. }
  239. }
  240. }
  241. }
  242. }
  243. // Scheduled message
  244. if ( $sender_info['type'] == 'TEACHER' && isset($message_data['scheduled']) && $message_data['scheduled'] ){
  245. $scheduled_message_id = ScheduledMessagesHandler::sendScheduledMessage($message_data, $attached_resources, $receivers, $sender_info);
  246. if ($use_response_obj_return) {
  247. $response_obj->setSuccessful();
  248. $response_obj->is_scheduled = true;
  249. $response_obj->message_id = 0;
  250. $response_obj->scheduled_message_id = $scheduled_message_id;
  251. return $response_obj;
  252. } else {
  253. return $scheduled_message_id;
  254. }
  255. }
  256. if(empty($message_data['posted_in'])) $message_data['posted_in'] = null;
  257. if(empty($message_data['posted_in_id'])) $message_data['posted_in_id'] = null;
  258. if(empty($message_data['comment_to'])) $message_data['comment_to'] = null;
  259. $message_data['other_reply_count'] = 0;
  260. if ($message_data['comment_to']) {
  261. $message_data['other_reply_count'] = ArrayHelper::elem(NewComments::getInstance()->getCommentCount(array($message_data['comment_to'])), $message_data['comment_to'], 1) - 1;
  262. }
  263. //--------------------------------
  264. // Clean up the Message Receiver arrays
  265. $this->last_direct_msg_receivers= array();
  266. $this->last_indirect_msg_receivers= array();
  267. // STORE MESSAGE
  268. $message = array(
  269. 'creator_id' => $sender_info['user_id'],
  270. 'type' => $message_data['type'],
  271. 'comment_to' => $message_data['comment_to']
  272. );
  273. if (isset($message_data['creation_date'])) {
  274. $message['creation_date'] = $message_data['creation_date'];
  275. }
  276. $message_id = Messages::getInstance()->store( $message );
  277. // send a 'community post' message to the activity stream
  278. // add to the user's share score
  279. if(isset($receivers['locations'])){
  280. foreach ( $receivers['locations'] as $location ){
  281. if($location['type']=='community'){
  282. //ActivityHandler::triggerCommunityPost($location['id'],$message_id,ActivityCommunityPost::TYPE_SUBJECT);
  283. ShareScore::getInstance()->incrementShareScoreByValue($sender_info['user_id'], 10);
  284. }
  285. }
  286. }
  287. /*
  288. if(isset($receivers['people'])){
  289. foreach($receivers['people'] as $user_id){
  290. $user=Users::getInstance()->find($user_id);
  291. if(isset($user[Users::TYPE]) && $user[Users::TYPE]==Users::TYPE_PUBLISHER){
  292. ActivityHandler::triggerCommunityPost($user_id,$message_id,ActivityCommunityPost::TYPE_PUBLISHER);
  293. }
  294. }
  295. }
  296. */
  297. // STORE THINGS ASSOCIATED WITH MESSAGE
  298. $store_message_data_response = $this->storeMessageData($message_id, $message_data, $sender_info, $receivers, $resource_resending, $attached_resources);
  299. if (isset($store_message_data_response['assignment_id'])) {
  300. $response_obj->assignment_id = $store_message_data_response['assignment_id'];
  301. }
  302. if (isset($store_message_data_response['quiz_run_id'])) {
  303. $response_obj->quiz_run_id = $store_message_data_response['quiz_run_id'];
  304. }
  305. $has_link_or_embed = $store_message_data_response['has_link_or_embed'];
  306. $message_data['has_community_relevance'] = $has_link_or_embed ? $this->hasCommunityRelevance($message_data) : false;
  307. $this->storeMessageReceiversNotification($sender_info, $message_id, $receivers, $message_data);
  308. // System messages for which a notification won't be sent
  309. $silent_system_messages = array('added-to-small-group', 'twitter-off-no-email', 'twitter-off-with-email');
  310. $send_system_message = true;
  311. foreach ( $silent_system_messages as $silent_system_message ){
  312. if ( strpos($message_data['message'], $silent_system_message) == false ){
  313. $send_system_message = false;
  314. break;
  315. }
  316. }
  317. // Notifications are sent
  318. if( ENABLE_EMAIL_NOTIFICATIONS && $message_data['type'] != MessagingHelper::MESSAGE_TYPE_FEED && $message_data['type'] != MessagingHelper::MESSAGE_TYPE_APP_MESSAGE && ($message_data['type'] != MessagingHelper::MESSAGE_TYPE_SYSTEM || $send_system_message ) ) {
  319. $message_data['message_id'] = $message_id;
  320. if ($message_data['type'] == 'quiz') {
  321. $quiz_info = Quiz::getInstance()->search(array('quiz_id' => $message_data['quiz_id']));
  322. $message_data['quiz_title'] = $quiz_info[0]['title'];
  323. $message_data['quiz_description'] = $quiz_info[0]['description'];
  324. }
  325. $message_data[TrackingHelper::DATA_DATE_REQUESTED] = time();
  326. $workerArray = array(
  327. 'message_data' => $message_data,
  328. 'selected_receivers' => $receivers,
  329. 'account_info' => $sender_info,
  330. 'server_name' => ENVIROMENT_DOMAIN //will now use this .ini variable that should be: "edmodo.com", "edmodoqa.com", or "clubmodo.com" for dev env
  331. );
  332. $serialized_data = serialize($workerArray);
  333. if ($this->use_gearman)
  334. {
  335. GearmanHelper::getInstance()->doBackgroundJob('sendNotifications', $serialized_data);
  336. }
  337. else
  338. {
  339. NotificationsWorker::send_notifications(new NotificationTestJob($serialized_data));
  340. }
  341. }
  342. $this->setMaxMessageIdForReceivers($sender_info['user_id'], $receivers, $message_id);
  343. // Add this post to the publisher's cached messages
  344. if ( $sender_info['type'] == 'PUBLISHER' ){
  345. Messages::getInstance()->cachePublisherMessageId( $sender_info['user_id'], $message_id );
  346. }
  347. $this->preProcessPossibleGdocs($message_data, $attached_resources);
  348. //Processing google docs
  349. if(isset($message_data['google_docs']) && !empty($message_data['google_docs']))
  350. {
  351. $google_handler = GoogleApiHandler::getInstance();
  352. if(isset($message_data['google_docs']['docs_info'])){
  353. }
  354. $docs_info = isset($message_data['google_docs']['docs_info']) ? $message_data['google_docs']['docs_info']: NULL;
  355. $role = isset($message_data['google_docs']['role']) ? $message_data['google_docs']['role']: NULL;
  356. $scope = isset($message_data['google_docs']['scope']) ? $message_data['google_docs']['scope']: NULL;
  357. $google_info = UsersGoogleInfo::getInstance()->getUserGoogleInfo( $sender_info["user_id"] );
  358. if(is_array($google_info))
  359. $full_info = array_merge($sender_info,$google_info);
  360. else
  361. $full_info = $sender_info;
  362. $message_data_tmp = $message_data;
  363. $message_data_tmp['message_id'] = $message_id;
  364. $message_data_tmp['obj_type'] = 'MESSAGE';
  365. $gdocs_links = $google_handler->setPermissionsForReceivers($docs_info,$receivers,$full_info,$role,$scope, $message_data_tmp);
  366. }
  367. if ($use_response_obj_return) {
  368. $response_obj->setSuccessful();
  369. $response_obj->is_moderated = false;
  370. $response_obj->message_id = $message_id;
  371. $response_obj->scheduled_message_id = 0;
  372. return $response_obj;
  373. } else {
  374. return $message_id;
  375. }
  376. }
  377. private function isSpammer($sender_info, $message_data){
  378. $is_spammer = false;
  379. $user_id = $sender_info['user_id'];
  380. if($message_data['type'] != 'feed' && $user_id != EDMODO_SYSTEM_USER_ID){
  381. $rate_limiter = RateLimitHandler::getInstance();
  382. $rate_limiter->increment('posts_per_user_per_hour', $user_id);
  383. if ($rate_limiter->isLimited('posts_per_user_per_hour', $user_id)) {
  384. $is_spammer = true;
  385. }
  386. }
  387. return $is_spammer;
  388. }
  389. public function sendComment($comment_data, $receivers, $sender_info, $check_send_rights = true, $bypass_moderation = false, $use_response_obj_return = false)
  390. {
  391. $response_obj = new HandlerResponseObj();
  392. if($check_send_rights){
  393. if ( $sender_info['user_id'] != EDMODO_SYSTEM_USER_ID && !$this->userHasRightsToSendMessage( $sender_info, $receivers, $comment_data, true )){
  394. if ($use_response_obj_return) {
  395. $response_obj->setUnsuccessful();
  396. $response_obj->addError('User does not have rights to reply to this message.');
  397. return $response_obj;
  398. } else {
  399. return false;
  400. }
  401. }
  402. }
  403. // check that the number of replies to this post has not exceeded the limit
  404. if(NewComments::getInstance()->postHasExceededReplyCount($comment_data['comment_to'])){
  405. // update the message's last updated timestamp to indicate that it should be re-fetched by clients that cache the data (e.g. Android App)
  406. if (!MessageData::getInstance()->updateMessageLastUpdatedTime($comment_data['comment_to'])) {
  407. throw new Exception('Failed to update message last updated timestamp');
  408. }
  409. if ($use_response_obj_return) {
  410. $response_obj->setUnsuccessful();
  411. $response_obj->reply_count_exceeded = true;
  412. $response_obj->addError('Reply count exceeded for this post.');
  413. return $response_obj;
  414. } else {
  415. return false;
  416. }
  417. }
  418. // Comments sent by students are only sent immediately if none of the recipients of the original message is a moderated group
  419. if ( !$bypass_moderation && !empty($receivers['locations']) ){
  420. $groups_db = Groups::getInstance();
  421. foreach ( $receivers['locations'] as $location ){
  422. if ( $location['type'] == 'group' ){
  423. $group = $groups_db->find($location['id'])->current();
  424. if ( $group['moderated'] && ( $sender_info['type'] == 'STUDENT' || !$groups_db->userOwnsGroup( $sender_info['user_id'], $group['group_id'], true )) ){
  425. // Post moderated message here
  426. $comment_data['group_id'] = $group['group_id'];
  427. ModeratedMessagesHandler::sendModeratedComment($comment_data, $receivers['locations'], $sender_info);
  428. if ($use_response_obj_return) {
  429. $response_obj->setSuccessful();
  430. $response_obj->is_moderated = true;
  431. $response_obj->comment_id = 0;
  432. return $response_obj;
  433. } else {
  434. return false;
  435. }
  436. }
  437. }
  438. }
  439. }
  440. if(empty($comment_data['posted_in'])) $comment_data['posted_in'] = null;
  441. if(empty($comment_data['posted_in_id'])) $comment_data['posted_in_id'] = null;
  442. $comment_data['type'] = 'comment';
  443. //--------------------------------
  444. // Clean up the Message Receiver arrays
  445. $this->last_direct_msg_receivers= array();
  446. $this->last_indirect_msg_receivers= array();
  447. // STORE MESSAGE
  448. $comment = array(
  449. 'creator_id' => $sender_info['user_id'],
  450. 'comment_to' => $comment_data['comment_to'],
  451. 'content' => $comment_data['message']
  452. );
  453. if (isset($comment_data['creation_date'])) {
  454. $comment['creation_date'] = $comment_data['creation_date'];
  455. }
  456. $comment_id = NewComments::getInstance()->store( $comment );
  457. $comment_data['other_reply_count'] = 0;
  458. if ($comment_data['comment_to']) {
  459. $comment_data['other_reply_count'] = ArrayHelper::elem(NewComments::getInstance()->getCommentCount(array($comment_data['comment_to'])), $comment_data['comment_to'], 1) - 1;
  460. }
  461. // Parse the assignment's description for latex math expressions and generate images
  462. LatexHandler::getInstance()->extractMathExpressions($comment_data['message']);
  463. $this->storeMessageReceiversNotification($sender_info, $comment_id, $receivers, $comment_data, true);
  464. if( ENABLE_EMAIL_NOTIFICATIONS ){
  465. $comment_data['comment_id'] = $comment_id;
  466. $comment_data[TrackingHelper::DATA_DATE_REQUESTED] = time();
  467. $workerArray = array(
  468. 'message_data' => $comment_data,
  469. 'selected_receivers'=> $receivers,
  470. 'account_info' => $sender_info,
  471. 'server_name' => $_SERVER['HTTP_HOST']
  472. );
  473. $serialized_data = serialize($workerArray);
  474. if ($this->use_gearman)
  475. {
  476. GearmanHelper::getInstance()->doBackgroundJob('sendNotifications', $serialized_data);
  477. }
  478. else
  479. {
  480. NotificationsWorker::send_notifications(new NotificationTestJob($serialized_data));
  481. }
  482. }
  483. $this->setMaxMessageIdForReceivers($sender_info['user_id'], $receivers, $comment_id, true);
  484. if ($use_response_obj_return) {
  485. $response_obj->setSuccessful();
  486. $response_obj->is_moderated = false;
  487. $response_obj->comment_id = $comment_id;
  488. return $response_obj;
  489. } else {
  490. return $comment_id;
  491. }
  492. }
  493. private function hasCommunityRelevance( $message_data ){
  494. $has_community_relevance = true;
  495. $unwanted_urls = array(
  496. 'spreadsheets.google.com',
  497. 'docs.google.com',
  498. 'chalk.edmodo.com',
  499. 'surveymonkey.com',
  500. 'pbworks.com',
  501. 'sites.google.com',
  502. 'coveritlive.com'
  503. );
  504. if (isset( $message_data['links'] )){
  505. foreach ( $message_data['links'] as $link ){
  506. foreach ( $unwanted_urls as $unwanted_url ){
  507. if ( strpos($link['url'], $unwanted_url) !== false ){
  508. $has_community_relevance = false;
  509. break;
  510. }
  511. }
  512. }
  513. }
  514. if ($has_community_relevance && isset( $message_data['embeds'] )){
  515. foreach ( $message_data['embeds'] as $embed ){
  516. foreach ( $unwanted_urls as $unwanted_url ){
  517. if ( strpos($embed['url'], $unwanted_url) !== false ){
  518. $has_community_relevance = false;
  519. break;
  520. }
  521. }
  522. }
  523. }
  524. return $has_community_relevance;
  525. }
  526. private function setMaxMessageIdForReceivers($sender_id, $receivers, $message_id, $is_comment = false){
  527. $cache_handler = MemcacheHandler::getInstance();
  528. if ( $cache_handler->cachingAvailable() ){
  529. $user_ids = array();
  530. $user_ids[] = $sender_id;
  531. if(isset($receivers['people']))
  532. {
  533. foreach( $receivers['people'] as $person ){
  534. $user_ids[] = $person;
  535. }
  536. }
  537. if(!empty($receivers['locations'])){
  538. foreach( $receivers['locations'] as $location ){
  539. switch( $location['type'] ){
  540. case 'all-groups':
  541. $groups_db = Groups::getInstance();
  542. $groups = $groups_db->getUserGroups($sender_id);
  543. foreach( $groups as $group ){
  544. $members = $groups_db->getGroupMembers($group['group_id'], true);
  545. if(count($members) < 100){
  546. //if the group is too big, don't do this
  547. foreach( $members as $member ){
  548. $user_ids[] = $member['user_id'];
  549. }
  550. }
  551. }
  552. break;
  553. case 'connections':
  554. $connections = Connections::getInstance()->getConnectedUserIds($sender_id);
  555. foreach( $connections as $connection_id ){
  556. $user_ids[] = $connection_id;
  557. }
  558. break;
  559. case 'all':
  560. $groups_db = Groups::getInstance();
  561. $groups = $groups_db->getUserGroups($sender_id);
  562. foreach( $groups as $group ){
  563. $members = $groups_db->getGroupMembers($group['group_id'], true);
  564. foreach( $members as $member ){
  565. $user_ids[] = $member['user_id'];
  566. }
  567. }
  568. $connections = Connections::getInstance()->getConnectedUserIds($sender_id);
  569. foreach( $connections as $connection_id){
  570. $user_ids[] = $connection_id;
  571. }
  572. break;
  573. case 'group':
  574. $members = Groups::getInstance()->getGroupMembers($location['id'], true);
  575. if(count($members) < 100){
  576. foreach( $members as $member ){
  577. $user_ids[] = $member['user_id'];
  578. }
  579. }
  580. break;
  581. case 'group-parents':
  582. $parents = ParentsStudents::getParents($location['id'], true);
  583. foreach( $parents as $parent ){
  584. $user_ids[] = $parent['parent_id'];
  585. }
  586. break;
  587. case 'school':
  588. $member_ids = Schools::getInstance()->getSchoolMembers($location['id']);
  589. if(count($member_ids) < 1000){
  590. $user_ids = array_merge($user_ids, $member_ids);
  591. }
  592. break;
  593. case 'school_vip':
  594. $member_ids = Schools::getInstance()->getSchoolMembers($location['id'], true, 'teachers-admins');
  595. $user_ids = array_merge($user_ids, $member_ids);
  596. break;
  597. case 'district':
  598. $member_ids = Districts::getInstance()->getDistrictMembers($location['id']);
  599. if(count($member_ids) < 2000){
  600. $user_ids = array_merge($user_ids, $member_ids);
  601. }
  602. break;
  603. case 'district_vip':
  604. $member_ids = Districts::getInstance()->getDistrictMembers($location['id'], true, 'teachers-admins');
  605. if(count($member_ids) < 1000){
  606. $user_ids = array_merge($user_ids, $member_ids);
  607. }
  608. break;
  609. }
  610. }
  611. }
  612. $max_identifier = 'max_message_id';
  613. if ( $is_comment ){
  614. $max_identifier = 'max_comment_id';
  615. }
  616. foreach( $user_ids as $user_id ){
  617. $cache_handler->save($message_id, $user_id.$max_identifier);
  618. }
  619. }
  620. }
  621. /**
  622. * Stores the message's data
  623. * @return array An array containing two keys: has_link_or_embed and assignment_id
  624. */
  625. private function storeMessageData
  626. ($message_id, $message_data, $sender_info, $receivers = null, $resource_resending = FALSE, $attached_resources = '')
  627. {
  628. $response = array();
  629. $has_link_or_embed = false;
  630. $content = $message_data['message'];
  631. // handle special post types
  632. switch ($message_data['type']){
  633. case ASSIGNMENT:
  634. // For some reason, message_data sometimes does not have this optional field.
  635. // Setting to NULL, because Assignments->store() checks to see if this field = NULL.
  636. if (empty($message_data['default_total'])) {
  637. $message_data['default_total'] = null;
  638. }
  639. // if lock_after_due is not specified, set it to 0 by default
  640. $lock_after_due = isset($message_data['lock_after_due']) ? $message_data['lock_after_due'] : 0;
  641. $assignment_id = Assignments::getInstance()->store($message_id, $message_data['assignment-description'], $message_data['due-date'], $message_data['default_total'], $lock_after_due);
  642. $response['assignment_id'] = $assignment_id;
  643. $content = $message_data[ASSIGNMENT];
  644. // Parse the assignment's description for latex math expressions and generate images
  645. LatexHandler::getInstance()->extractMathExpressions($message_data['assignment-description']);
  646. break;
  647. case 'quiz':
  648. $quiz_info = Quiz::getInstance()->search(array('quiz_id' => $message_data['quiz_id']));
  649. $record = array
  650. (
  651. QuizRun::QUIZ_ID=>$message_data['quiz_id'],
  652. QuizRun::DUE_DATE=>$message_data['quiz-due-date'],
  653. QuizRun::AUTO_GRADE=>'1',
  654. QuizRun::SAVE_TO_GRADEBOOK=>$message_data['auto-grade'],
  655. QuizRun::MESSAGE_ID=>$message_id,
  656. QuizRun::SHOW_RESULTS=>$quiz_info[0]['show_results'],
  657. QuizRun::TIME_LIMIT=>$quiz_info[0]['time_limit'],
  658. QuizRun::STATUS=>QuizRun::STATUS_ASSIGNED,
  659. );
  660. $quizRunModel=QuizRun::getInstance();
  661. $quiz_run_id=$quizRunModel->store($record);
  662. //delete any 'preview' quiz_runs for this $quiz_id
  663. $quiz_runs=$quizRunModel->search(array(QuizRun::QUIZ_ID=>$message_data['quiz_id'],QuizRun::PREVIEW=>'1'));
  664. foreach($quiz_runs as $quiz_run){
  665. $quizRunModel->delete($quiz_run[QuizRun::QUIZ_RUN_ID]);
  666. }
  667. $response['quiz_run_id'] = $quiz_run_id;
  668. $content = '';
  669. break;
  670. case 'poll':
  671. // insert the answers as well...
  672. PollAnswers::getInstance()->storeAnswers($message_id, $message_data['poll_answers']);
  673. $content = $message_data['poll_question'];
  674. break;
  675. default:
  676. break;
  677. }
  678. // Parse the message's content for latex math expressions and generate images
  679. LatexHandler::getInstance()->extractMathExpressions($content);
  680. // Message data is stored in the database
  681. $data = array
  682. (
  683. 'message_id' => $message_id,
  684. 'content' => $content //if it's a link, it's the same as the link's title, for now
  685. );
  686. MessageData::getInstance()->store( $data );
  687. if( ! empty($message_data['links']) )
  688. {
  689. $has_link_or_embed = true;
  690. // Store links
  691. LinkHandler::getInstance()->processAttachedLinks($message_data['links'],$message_id,$sender_info,$receivers, 'MESSAGE', $message_data['type']);
  692. }
  693. if( ! empty($message_data['files']) ){
  694. // Store files
  695. FileHandler::getInstance()->processAttachedFiles($message_data['files'],$message_id,$sender_info,$receivers);
  696. }
  697. if (is_array($attached_resources)) {
  698. foreach ($attached_resources as $item_id) {
  699. $item_info = LibraryItems::getInstance()->getLibraryItem($item_id);
  700. if ($sender_info['type'] != 'PUBLISHER') {
  701. LibraryItems::getInstance()->updateRelations($item_id, $receivers);
  702. }
  703. if ($item_info['library_item_type'] == 'FILE') {
  704. MessagesFiles::getInstance()->store(array('message_id' => $message_id, 'file_id' => $item_info['library_item_resource_id']));
  705. } else if ($item_info['library_item_type'] == 'LINK') {
  706. MessagesLinks::getInstance()->store(array('message_id' => $message_id, 'link_id' => $item_info['library_item_resource_id']));
  707. $has_link_or_embed = true;
  708. } else if ($item_info['library_item_type'] == 'EMBED') {
  709. MessagesEmbeds::getInstance()->store(array('message_id' => $message_id, 'embed_id' => $item_info['library_item_resource_id']));
  710. $has_link_or_embed = true;
  711. }
  712. }
  713. }
  714. $response['has_link_or_embed'] = $has_link_or_embed;
  715. return $response;
  716. }
  717. /**
  718. * Stores the corresponding notifications for a message's receivers
  719. * @param $sender_info is the message's sender info
  720. * @param $message_origin is the location where the message was posted
  721. * @param $receivers is an array with all the message's receivers
  722. */
  723. private function storeMessageReceiversNotification($sender_info, $message_id, $receivers, $message_data, $is_comment = false){
  724. $locations = null;
  725. $message_sent_to_group = false;
  726. if(!empty($receivers['locations'])){
  727. $message_sent_to_group = true;
  728. $locations = $receivers['locations'];
  729. }
  730. $message_data[TrackingHelper::DATA_DATE_REQUESTED] = time();
  731. $db_recipients_array = array();
  732. if($message_sent_to_group) {
  733. $this->checkIfMessageSentToEveryone($sender_info, $locations);
  734. $already_cached_in_community = array();
  735. $communities_model = SubjectCommunities::getInstance();
  736. $all_community_ids = $communities_model->getSubjectCommunityIds();
  737. $is_verified_teacher = false;
  738. if($sender_info['type'] == 'TEACHER'){
  739. $is_verified_teacher = CoppaHandler::userIsCoppaVerified($sender_info['user_id']);
  740. }
  741. foreach($locations as $location) {
  742. //store this message location...
  743. if ( $location['type'] == 'connections' ){
  744. // Messages sent to connections have the sender's user id in the posted_in_id field of message_recipients_connections
  745. $location['id'] = $sender_info['user_id'];
  746. }
  747. $recipient = array(
  748. 'type' => $location['type'],
  749. 'message_id' => $message_id,
  750. 'posted_in_id' => $location['id'],
  751. );
  752. $db_recipients_array[] = $recipient;
  753. switch( $location['type'] )
  754. {
  755. case 'group':
  756. case 'GROUP':
  757. $this->setGroupLastMessageReceivers($location['id']);
  758. if ( !$is_comment ){
  759. Messages::getInstance()->cacheGroupMessageId($location['id'], $message_id);
  760. }
  761. break;
  762. case 'group_parents':
  763. case 'GROUP_PARENTS':
  764. if ( !$is_comment ){
  765. Messages::getInstance()->cacheGroupMessageId($location['id'], $message_id);
  766. // If the message was sent to a group's parents receiver (and not to the group itself), its message_id
  767. // is stored in a cached array later used to avoid displaying it to students viewing the group's stream
  768. $message_sent_to_group_parents_only = true;
  769. foreach($locations as $other_location){
  770. if ( ($other_location['type'] == 'group' || $other_location['type'] == 'GROUP') && $other_location['id'] == $location['id'] ){
  771. $message_sent_to_group_parents_only = false;
  772. break;
  773. }
  774. }
  775. if ( $message_sent_to_group_parents_only ){
  776. Messages::getInstance()->cacheGroupParentsMessageId($location['id'], $message_id);
  777. }
  778. }
  779. break;
  780. case 'connections':
  781. $this->setConnectionsLastMessageReceivers($sender_info['user_id']);
  782. break;
  783. case 'community':
  784. if( $is_verified_teacher &&
  785. $message_data['type'] != 'comment' &&
  786. !isset($already_cached_in_community[$location['id']])){
  787. Messages::getInstance()->cacheCommunityMessageId($location['id'], $message_id);
  788. $already_cached_in_community[$location['id']] = true;
  789. }
  790. if($location['id'] == SUPPORT_COMMUNITY_ID && !$is_comment){
  791. //Send an email to the support address
  792. $title = 'Post from ' . $sender_info['first_name'] . ' ' . $sender_info['last_name'] . ' (' . $sender_info['username'] . ')';
  793. $body_text = $message_data['message'];
  794. $recipients = array(
  795. array(
  796. 'email' => SUPPORT_COMMUNITY_EMAIL,
  797. 'username' => 'Support',
  798. ),
  799. );
  800. $tracking_data = TrackingHelper::makeTrackingData(TrackingHelper::EMAILTYPE_SUPPORT_COMMUNITY__NOTIFICATION, null, null, TrackingHelper::TYPE_SYSTEM, null, TrackingHelper::TYPE_INTERNAL, SUPPORT_COMMUNITY_EMAIL, $message_id, TrackingHelper::TYPE_MESSAGE);
  801. MailHandler::getInstance($body_text)->setTrackingData($tracking_data)->sendEmailWrapper($recipients, $title);
  802. }
  803. break;
  804. }
  805. }
  806. }
  807. $people_count = 0;
  808. if (isset($receivers['people'])){
  809. $people_count = count($receivers['people']);
  810. }
  811. if($people_count > 0){
  812. //add direct notifications for people
  813. if($people_count == 1){
  814. $receiver_info = Users::getInstance()->find($receivers['people'][0]);
  815. if ( $receiver_info['type'] == 'PUBLISHER' ){
  816. Messages::getInstance()->cachePublisherMessageId( $receiver_info['user_id'], $message_id );
  817. }
  818. }
  819. foreach($receivers['people'] as $user_id){
  820. $recipient = array(
  821. 'type' => 'user',
  822. 'message_id' => $message_id,
  823. 'posted_in_id' => $user_id,
  824. );
  825. $db_recipients_array[] = $recipient;
  826. $this->last_direct_msg_receivers[] = $user_id;
  827. $this->last_message_receivers[] = $user_id;
  828. }
  829. }
  830. // this is what actually writes to the message_recipients_* tables for the given message_id
  831. if ( !$is_comment ){
  832. Messages::getInstance()->bulkStore($db_recipients_array);
  833. }
  834. }
  835. /**
  836. * Check if a message was sent to Everyone (all the user's groups)
  837. */
  838. private function checkIfMessageSentToEveryone($sender_info, &$locations){
  839. $all_groups = $all_connections = false;
  840. $list = $locations;
  841. foreach ($list as $i => $location) {
  842. switch ($location['type']) {
  843. case 'all-groups':
  844. $all_groups = true;
  845. $locations = array();
  846. break;
  847. case 'connections':
  848. $all_connections = true;
  849. unset($locations[$i]);
  850. break;
  851. case 'all':
  852. // the message was sent to everyone
  853. $all_groups = true;
  854. $all_connections = true;
  855. unset($locations[$i]);
  856. break;
  857. default:
  858. }
  859. }
  860. if($all_groups){
  861. //send to all the user's groups
  862. $all_user_groups = Groups::getInstance()->getUserGroups($sender_info['user_id'], false, false);
  863. foreach($all_user_groups as $group){
  864. //new rule - the user must own the group in order to send the message
  865. if ($group['read_only'] != 1 && !empty($group['user_owns_group'])) {
  866. $locations[] = array('type' => GROUP, 'id' => $group['group_id']);
  867. }
  868. }
  869. }
  870. if($all_connections && ($sender_info['type'] == 'TEACHER' || $sender_info['type'] == 'PUBLISHER')){
  871. //send to all the teacher's connections
  872. $locations[] = array('type' => 'connections', 'id' => 0);
  873. }
  874. }
  875. /*
  876. * Adds the corresponding user_ids to the last_indirect_msg_receivers array (for spotlight purposes)
  877. */
  878. private function setConnectionsLastMessageReceivers($sender_id)
  879. {
  880. $user_ids = Connections::getInstance()->getConnectedUserIds($sender_id);
  881. foreach($user_ids as $user_id){
  882. $this->last_indirect_msg_receivers[] = $user_id;
  883. $this->last_message_receivers[] = $user_id;
  884. }
  885. }
  886. /*
  887. * Adds the corresponding user_ids to the last_indirect_msg_receivers array (for spotlight purposes)
  888. */
  889. private function setGroupLastMessageReceivers($group_id){
  890. $user_ids = Groups::getInstance()->getUserIds($group_id);
  891. foreach($user_ids as $user_id){
  892. $this->last_indirect_msg_receivers[] = $user_id;
  893. $this->last_message_receivers[] = $user_id;
  894. }
  895. }
  896. /**
  897. * Returns a list of user_ids who received the last message
  898. * @return array
  899. */
  900. public function getLastMessageReceivers()
  901. {
  902. $last_msg_receivers = array_merge($this->last_direct_msg_receivers,$this->last_indirect_msg_receivers);
  903. return $last_msg_receivers;
  904. }
  905. /**
  906. * Returns a list of direct user_ids who received the last message
  907. * @return array
  908. */
  909. public function getLastMessageDirectReceivers()
  910. {
  911. return $this->last_direct_msg_receivers;
  912. }
  913. /*
  914. * Modifies the contents of a mesage
  915. * $params string message_id is the id of the message to edit
  916. */
  917. public function editMessage($message_id, $content, $link_id = null, $new_url = null){
  918. if(!empty($link_id)){
  919. Links::getInstance()->editLink($link_id, $new_url);
  920. }
  921. MessageData::getInstance()->editMessage($message_id, $content);
  922. // Parse the message's content for latex math expressions and generate images
  923. LatexHandler::getInstance()->extractMathExpressions($content);
  924. }
  925. public function checkFilteredMessages($language, &$filters, $library_button = false, $get_community_counters = false, $get_html = false, $view = null)
  926. {
  927. $result = array();
  928. $the_filters = array
  929. (
  930. 'get_all_messages' => (!isset($filters['all_msgs']) || $filters['all_msgs'] == 'true') ? true : false,
  931. 'get_comments_only' => (!isset($filters['comments_only']) || $filters['comments_only'] == 'false') ? false : true,
  932. 'search_str' => isset($filters['search_str']) ? $filters['search_str'] : '',
  933. 'people_filter' => (!isset($filters['people_filter']) || $filters['people_filter'] == 'null') ? 'EVERYONE' : $filters['people_filter'],
  934. 'group_id' => (!isset($filters['group_id']) || $filters['group_id'] == 'null') ? null : $filters['group_id'],
  935. 'direct_user_id' => (!isset($filters['direct_user_id']) || $filters['direct_user_id'] == 'null') ? null : $filters['direct_user_id'],
  936. 'tag_id' => (!isset($filters['tag_id']) || $filters['tag_id'] == 'null') ? null : $filters['tag_id'],
  937. 'community_id' => (!isset($filters['community_id']) || $filters['community_id'] == 'null') ? null : $filters['community_id'],
  938. 'include_communities' => (!isset($filters['include_communities']) || $filters['include_communities'] == 'null') ? null : $filters['include_communities'],
  939. 'connections' => (!isset($filters['connections']) || $filters['connections'] == 'null') ? null : $filters['connections'],
  940. 'publishers' => (!isset($filters['publishers']) || $filters['publishers'] == 'null') ? null : $filters['publishers'],
  941. 'current_last_msg_id' => isset($filters['current_last_msg_id']) ? $filters['current_last_msg_id'] : 0,
  942. 'max_messages' => isset($filters['max_messages']) ? $filters['max_messages'] : 20,
  943. 'page' => isset($filters['page']) ? $filters['page'] : false,
  944. 'sqllimit' => isset($filters['sqllimit']) ? true : false,
  945. 'max_message_id' => (!isset($filters['max_message_id']) || $filters['max_message_id'] == 'null') ? null : $filters['max_message_id'],
  946. 'max_comment_id' => (!isset($filters['max_comment_id']) || $filters['max_comment_id'] == 'null') ? null : $filters['max_comment_id'],
  947. 'public_only' => (!isset($filters['public_only']) || $filters['public_only'] == 'false' || !$filters['public_only']) ? false : true,
  948. 'sender_id' => isset($filters['sender_id']) ? $filters['sender_id'] : false,
  949. 'user_feed_id' => (!isset($filters['user_feed_id']) || $filters['user_feed_id'] == 'null') ? null : $filters['user_feed_id'],
  950. 'students_info_for_parent' => isset($filters['students_info_for_parent'])? $filters['students_info_for_parent'] : null,
  951. 'parents' => isset($filters['parents'])? $filters['parents'] : null,
  952. 'is_inst_subdomain' => isset($filters['is_inst_subdomain'])? $filters['is_inst_subdomain'] : false,
  953. 'message_ids_in_stream' => isset($filters['message_ids_in_stream']) && !empty($filters['message_ids_in_stream'])? $filters['message_ids_in_stream'] : null,
  954. 'get_school_vip_msgs' => isset($filters['get_school_vip_msgs'])? $filters['get_school_vip_msgs'] : false,
  955. 'trending_posts' => isset($filters['trending_posts'])? $filters['trending_posts'] : false,
  956. 'max_spotlight_id' => (!isset($filters['max_spotlight_id']) || $filters['max_spotlight_id'] == 'null') ? null : $filters['max_spotlight_id']
  957. );
  958. //Set the message feed type to HOME_FEED if it's the case:
  959. if(empty($the_filters['people_filter']) || $the_filters['people_filter'] == 'EVERYONE'){
  960. $this->setFeedType('HOME_FEED');
  961. }
  962. $account_info = AccountHandler::getInstance()->getAccountInfo();
  963. $user_community_ids = null;
  964. $publisher_ids = null;
  965. $user_hidden_homestream_communities = array();
  966. $user_hidden_homestream_publishers = array();
  967. if( !$the_filters['public_only'] ){
  968. if ( empty($account_info) ){
  969. $account_info = null;
  970. }else{
  971. if($account_info['type'] == 'PARENT' && !isset($the_filters['students_info_for_parent'])){
  972. //Need to retrieve the parent's children's groups
  973. $students_groups = array();
  974. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo($account_info, $the_filters['user_feed_id']);
  975. if(count($students_info['student_ids'])){
  976. $the_filters['students_info_for_parent'] = ParentsHandler::getInstance()->getStudentsGroupsForParent($students_info);
  977. }
  978. }else if ($account_info['type'] == 'TEACHER'){
  979. if($this->feed_type == 'HOME_FEED'){
  980. $user_hidden_homestream_communities = UsersHomestreamHiddenCommunities::getInstance()->getUserHomestreamHiddenCommunities($account_info['user_id']);
  981. $user_hidden_homestream_publishers = UsersHomestreamHiddenConnections::getInstance()->getUserHomestreamHiddenConnections($account_info['user_id']);
  982. $is_admin = false;
  983. $support_team = SubjectCommunityHandler::getInstance($language)->getSupportTeam($language);
  984. if($account_info['admin_rights'] == 'SCHOOL' || $account_info['admin_rights'] == 'DISTRICT')
  985. {
  986. $is_admin = true;
  987. }
  988. foreach($support_team as $member){
  989. if($member['user_id'] == $account_info['user_id'])
  990. {
  991. $is_admin = true;
  992. break;
  993. }
  994. }
  995. $user_community_ids = SubjectCommunities::getInstance()->getUsersSubjectComms($account_info['user_id'], true, $is_admin, true);
  996. $publishers_info = ConnectionsHandler::getInstance()->getPublisherConnectionsInfo($account_info['user_id']);
  997. $publisher_ids = $publishers_info['publisher_ids'];
  998. if(!isset($the_filters['include_communities'])){
  999. $the_filters['include_communities'] = array_diff($user_community_ids, $user_hidden_homestream_communities);
  1000. }
  1001. if(!isset($the_filters['connections'])){
  1002. $the_filters['connections'] = Connections::getInstance()->getConnectedUserIds($account_info['user_id']);
  1003. $the_filters['connections'] = array_diff($the_filters['connections'], UsersHomestreamHiddenConnections::getInstance()->getUserHomestreamHiddenConnections($account_info['user_id']));
  1004. }
  1005. if(!isset($the_filters['publishers'])){
  1006. $the_filters['publishers'] = array_diff( $publisher_ids, $user_hidden_homestream_publishers);
  1007. }
  1008. }
  1009. }
  1010. elseif( $account_info['type'] == 'ADMINISTRATOR' && !isset($user_community_ids) ){
  1011. $subject_communities_info = SubjectCommunityHandler::getInstance($language)->getUsersSubjectCommunities($account_info['user_id'],true);
  1012. $user_community_ids = $subject_communities_info['subject_community_ids'];
  1013. }
  1014. }
  1015. }
  1016. $the_filters['viewer_and_viewed_info'] = $this->getInfoAboutViewerAndViewed($account_info, $the_filters);
  1017. if (isset($the_filters['user_feed_id'])) {
  1018. $feed_user = Users::getInstance()->getUserInfo($the_filters['user_feed_id']);
  1019. if ($feed_user['type'] == 'PUBLISHER')
  1020. {
  1021. $library_button = true;
  1022. }
  1023. }
  1024. $msg_filter = (!isset($filters['msgs_type']) || $filters['msgs_type'] == 'null') ? null : $filters['msgs_type'];
  1025. if( $msg_filter == 'link' ){
  1026. $msg_filter = array( 'link', 'video', 'embed' );
  1027. }
  1028. $the_filters['msgs_type'] = $msg_filter;
  1029. $memcache_handler = MemcacheHandler::getInstance();
  1030. $get_new_messages = !$memcache_handler->cachingAvailable()
  1031. || $the_filters['get_all_messages']
  1032. || $the_filters['max_message_id'] == null
  1033. || ($the_filters['people_filter'] == 'COMMUNITY' && $the_filters['community_id'] == SUPPORT_COMMUNITY_ID && !$the_filters['get_comments_only'])
  1034. || ($the_filters['people_filter'] == 'COMMUNITY' && $the_filters['community_id'] == ADMIN_SUPPORT_COMMUNITY_ID && !$the_filters['get_comments_only'])
  1035. || ($account_info != null && $the_filters['people_filter'] == 'COMMUNITY' && SubjectCommunityHandler::getInstance()->newMessagesInCommunity($account_info['user_id'], $the_filters['community_id']))
  1036. || ($account_info != null && !$the_filters['trending_posts'] && !$the_filters['get_comments_only'] && MemcacheHandler::getInstance()->load($account_info['user_id'].'max_message_id') > $the_filters['max_message_id']);
  1037. if($get_community_counters && !empty($account_info) && $account_info['type'] == 'TEACHER' && $this->feed_type == 'HOME_FEED' && !$the_filters['get_comments_only']){
  1038. //check if new messages were posted to a community/publisher that this user follows
  1039. $community_counters = SubjectCommunityHandler::getInstance()->getCommunityCounters( $account_info['user_id'], $user_community_ids, $user_hidden_homestream_communities );
  1040. $publisher_counters = PublisherNewMessages::getInstance()->getPublisherCounters( $account_info['user_id'], $publisher_ids, $user_hidden_homestream_publishers );
  1041. if($community_counters['count_total'] > 0 || $publisher_counters['count_total'] > 0){
  1042. $get_new_messages = true;
  1043. }
  1044. }
  1045. if ( $get_new_messages && $this->userHasRightsToCheckMessages($account_info, $the_filters) ){
  1046. $result = $this->checkMessages($language, $account_info, $the_filters, $library_button);
  1047. }
  1048. if(!$the_filters['get_all_messages'] && !empty($the_filters['message_ids_in_stream'])){
  1049. if( !$memcache_handler->cachingAvailable()
  1050. || $the_filters['max_comment_id'] == null
  1051. || ($the_filters['people_filter'] == 'COMMUNITY' && $the_filters['community_id'] == SUPPORT_COMMUNITY_ID)
  1052. || ($the_filters['people_filter'] == 'COMMUNITY' && $the_filters['community_id'] == ADMIN_SUPPORT_COMMUNITY_ID)
  1053. || MemcacheHandler::getInstance()->load($account_info['user_id'].'max_comment_id') > $the_filters['max_comment_id'])
  1054. {
  1055. //Get comments too
  1056. self::initializeTranslators($language);
  1057. $comments = CommentsHandler::getInstance()->checkComments($this, $language, $the_filters, $this->institutional_info);
  1058. $result = array_merge($result, $comments);
  1059. }
  1060. }
  1061. // The html of the message list is added to the response object
  1062. if ( $get_html ){
  1063. $thumb_url = '';
  1064. if (!empty($the_filters['viewer_and_viewed_info'])){
  1065. $profile = Profiles::getInstance()->find($the_filters['viewer_and_viewed_info']['viewer_id'])->current();
  1066. $thumb_url = Profiles::getInstance()->getAvatarUrlFromProfile($profile, null, 'THUMB');
  1067. $full_avatar_url = Profiles::getInstance()->getAvatarUrlFromProfile($profile, null, '');
  1068. }
  1069. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'message-feed.tmx', $language);
  1070. if ( SECONDARY_THEME_ENABLED ){
  1071. $view->setScriptPath('../application/views/scripts_v2');
  1072. }
  1073. $html = $view->partial(
  1074. PATH2_PARTIALS.'message_feed/message-list.phtml',
  1075. array(
  1076. 'account_info' => AccountHandler::getInstance()->getAccountInfo(),
  1077. 'activities' => $result,
  1078. 'activity_count' => count($result),
  1079. 'max_activities' => $the_filters['max_messages'],
  1080. 'translator' => $translator,
  1081. 'new_comment_ids' => array(),
  1082. 'is_a_template' => false,
  1083. 'is_spotlight' => false,
  1084. 'can_create_tags' => ($this->feed_type == 'COMMUNITY_FEED' && $this->community_user_status == ADMINS),
  1085. 'is_community' => ($this->feed_type == 'COMMUNITY_FEED'),
  1086. 'public_only' => $the_filters['public_only'],
  1087. 'thumb_url' => $thumb_url,
  1088. 'full_avatar_url' => $full_avatar_url,
  1089. 'is_ipad' => (bool) strpos($_SERVER['HTTP_USER_AGENT'],'iPad'),
  1090. 'language' => $language
  1091. )
  1092. );
  1093. //$html = utf8_encode($html);
  1094. $result = array_merge($result, array(array('object_type'=>'message_list_html', 'message_list_html'=>$html)));
  1095. $full_message_partial = 'full-message';
  1096. // We'll now also add individual html for each message
  1097. foreach ( $result as $index => $activity ){
  1098. if ( $activity['object_type'] == 'message' ){
  1099. $result[$index]['html'] = $view->partial(
  1100. PATH2_PARTIALS.'message_feed/'.$full_message_partial.'.phtml',
  1101. array(
  1102. 'account_info' => $account_info,
  1103. 'activity' => $activity,
  1104. 'activities' => $result,
  1105. 'index' => $index,
  1106. 'translator' => $translator,
  1107. 'new_comment_ids' => array(),
  1108. 'is_a_template' => false,
  1109. 'is_spotlight' => false,
  1110. 'can_create_tags' => ($this->feed_type == 'COMMUNITY_FEED' && $this->community_user_status == ADMINS),
  1111. 'is_community' => ($this->feed_type == 'COMMUNITY_FEED'),
  1112. 'public_only' => $the_filters['public_only'],
  1113. 'thumb_url' => $thumb_url,
  1114. 'is_ipad' => (bool) strpos($_SERVER['HTTP_USER_AGENT'],'iPad'),
  1115. 'language' => $language
  1116. )
  1117. );
  1118. }
  1119. elseif ( $activity['object_type'] == 'comment' ){
  1120. $result[$index]['html'] = $view->partial(
  1121. PATH2_PARTIALS."message_feed/comment.phtml",
  1122. array(
  1123. 'activity' => $activity,
  1124. 'avatar_url'=>$thumb_url,
  1125. 'translator' => $translator,
  1126. 'is_a_template' => false,
  1127. 'public_only' => $the_filters['public_only'],
  1128. 'new_comment_ids' => array(),
  1129. 'language'=>$language
  1130. )
  1131. );
  1132. }
  1133. }
  1134. }
  1135. // Community counters are added to the result
  1136. if($get_new_messages && isset($community_counters['counters'], $publisher_counters['counters'])){
  1137. $result = array_merge($community_counters['counters'], $publisher_counters['counters'], $result);
  1138. }
  1139. // Spotlight counters are added to the result
  1140. if ( $get_community_counters && !empty($account_info) && $account_info['type'] != 'ADMINISTRATOR' && !empty($the_filters['max_spotlight_id']) && (!$memcache_handler->cachingAvailable() || !$memcache_handler->load($account_info['user_id'].'spotlights_up_to_date')) ){
  1141. $new_spotlight_counters = Spotlights::getInstance()->getNewSpotlightCounters($account_info['user_id'], $the_filters['max_spotlight_id']);
  1142. $result = array_merge($new_spotlight_counters, $result);
  1143. }
  1144. //------------------------
  1145. // Transform some of the filters for the FeedHandler.js
  1146. // turn the msg type to a single type
  1147. if( isset($filters['msgs_type']) && $filters['msgs_type'] == 'link')
  1148. {
  1149. $the_filters['msgs_type'] = 'link';
  1150. }
  1151. if( $the_filters['group_id'] != null )
  1152. {
  1153. $the_filters['people_filter_id'] = $the_filters['group_id'];
  1154. }
  1155. elseif ( $the_filters['sender_id'] != null )
  1156. {
  1157. $the_filters['people_filter_id'] = $the_filters['sender_id'];
  1158. }
  1159. else
  1160. {
  1161. $the_filters['people_filter_id'] = null;
  1162. }
  1163. if( isset($filters['header_title']) && isset($filters['header_color']) )
  1164. {
  1165. $the_filters['header_title'] = $filters['header_title'];
  1166. $the_filters['header_color'] = $filters['header_color'];
  1167. }
  1168. $filters = $the_filters;
  1169. return $result;
  1170. }
  1171. // Checks if the user represented by $account_info has rights to check messages with $filters
  1172. public function userHasRightsToCheckMessages($account_info, $filters){
  1173. $user_has_rights_to_check_messages = true;
  1174. switch ( $filters['people_filter'] ) {
  1175. case 'GROUP':
  1176. // Check if the user belongs to the group
  1177. if (!Groups::getInstance()->userBelongsToGroupById($account_info['user_id'], $filters['group_id']))
  1178. $user_has_rights_to_check_messages = false;
  1179. // Check if the group is enabled
  1180. if ($user_has_rights_to_check_messages) {
  1181. $group = Groups::getInstance()->find($filters['group_id'])->current();
  1182. if ( !$group['enabled'] )
  1183. $user_has_rights_to_check_messages = false;
  1184. }
  1185. break;
  1186. }
  1187. return $user_has_rights_to_check_messages;
  1188. }
  1189. /**
  1190. * Checks all messages sent to / received by this user
  1191. * @param string $language defines the viewing user's language
  1192. * @param array $account_info is the base user for message retrieval. Might be null (ie public feed)
  1193. * @param array $filters contains all the info about the query's filters:
  1194. * boolean 'get_all_messages' if false, function retrieves only the messages which have not been previously retrieved by this user. If true, function retrieves all messages.
  1195. * string 'search_str' a string to search in the messages
  1196. * string 'msgs_type' tells what to fetch: Assignments, Alerts, Polls, etc...
  1197. * string 'people_filter' tells whose msgs to fetch: Everything, Direct msgs, group messages, etc..
  1198. * string 'direct_user_id' used when $people_filter == 'DIRECT' to specify the user to which the direct messages have been sent or received
  1199. * int 'group_id' id for the group whose messages should be fetched
  1200. * int 'tag_id id' for the tag whose messages should be fetched
  1201. * boolean $public_only if true, function retrieves only the messages which have been set as public
  1202. * int 'message_id' id(s) for the message that has to be retrieved (along with its comments)
  1203. * int 'sender_id' id of the author of the messages that have to be retrieved
  1204. * int 'max_messages' max pagination result count for the retrieved messages
  1205. * int 'max_message_id' is the highest current message_id displayed in the user's feed
  1206. * int 'current_last_msg_id' when viewing More messages, the last message id currently shown in the stream (starting message id for additional messages)
  1207. * array 'include_communities' includes the community ids the user is part of, whose posts need to be retrieved for the stream
  1208. * array 'connections' includes the user ids the user is connected to, whose posts need to be retrieved for the stream
  1209. * array 'students_info_for_parent' for parent feeds, includes the info of the parent's students
  1210. * array 'parents' mainly for teachers' feeds, includes the info of the students' parents
  1211. * boolean 'edmodo_messages_only' will return back the plain message records without additional message information, recievers, or other message processing
  1212. * EXPERIMENTAL: int 'message_id_upper_bound' used to restrict the messages by message_id, this upper bound message id will restrict the query to fetch messages older than this id
  1213. * @return array with each message info grouped by message_id
  1214. */
  1215. public function checkMessages($language, $account_info = null, $filters = array(), $library_button = false){
  1216. //Set the default filters if they aren't set
  1217. $filters['get_all_messages'] = isset($filters['get_all_messages'])? $filters['get_all_messages'] : false;
  1218. $filters['search_str'] = isset($filters['search_str'])? addslashes($filters['search_str']) : '';
  1219. $filters['msgs_type'] = isset($filters['msgs_type'])? $filters['msgs_type'] : null;
  1220. $filters['people_filter'] = isset($filters['people_filter'])? $filters['people_filter'] : 'EVERYONE';
  1221. $filters['direct_user_id'] = isset($filters['direct_user_id'])? $filters['direct_user_id'] : null;
  1222. $filters['group_id'] = isset($filters['group_id'])? $filters['group_id'] : null;
  1223. $filters['community_id'] = isset($filters['community_id'])? $filters['community_id'] : null;
  1224. $filters['tag_id'] = isset($filters['tag_id'])? $filters['tag_id'] : null;
  1225. $filters['public_only'] = isset($filters['public_only'])? $filters['public_only'] : false;
  1226. $filters['by_teachers'] = isset($filters['by_teachers'])? $filters['by_teachers'] : false;
  1227. $filters['by_students'] = isset($filters['by_students'])? $filters['by_students'] : false;
  1228. $filters['by_me'] = isset($filters['by_me'])? $filters['by_me'] : false;
  1229. $filters['message_id'] = isset($filters['message_id'])? $filters['message_id'] : null;
  1230. $filters['sender_id'] = isset($filters['sender_id'])? $filters['sender_id'] : null;
  1231. $filters['current_last_msg_id'] = isset($filters['current_last_msg_id']) ? $filters['current_last_msg_id'] : 0;
  1232. $filters['max_messages'] = isset($filters['max_messages'])? $filters['max_messages'] : 20;
  1233. $filters['max_message_id'] = isset($filters['max_message_id'])? $filters['max_message_id'] : 0;
  1234. $filters['include_comments'] = isset($filters['include_comments'])? $filters['include_comments'] : true;
  1235. $filters['feed_type'] = $this->feed_type;
  1236. $filters['user_feed_id'] = isset($filters['user_feed_id'])? $filters['user_feed_id'] : false;
  1237. $filters['include_communities'] = isset($filters['include_communities'])? $filters['include_communities'] : null;
  1238. $filters['connections'] = isset($filters['connections'])? $filters['connections'] : null;
  1239. $filters['publishers'] = isset($filters['publishers'])? $filters['publishers'] : null;
  1240. $filters['students_info_for_parent'] = isset($filters['students_info_for_parent'])? $filters['students_info_for_parent'] : null;
  1241. $filters['archived_group_ids'] = isset($filters['archived_group_ids'])? $filters['archived_group_ids'] : array();
  1242. $filters['parents'] = isset($filters['parents'])? $filters['parents'] : null;
  1243. $filters['is_inst_subdomain'] = isset($filters['is_inst_subdomain'])? $filters['is_inst_subdomain'] : false;
  1244. $filters['get_school_vip_msgs'] = isset($filters['get_school_vip_msgs'])? $filters['get_school_vip_msgs'] : false;
  1245. $filters['trending_posts'] = isset($filters['trending_posts'])? $filters['trending_posts'] : false;
  1246. $filters['viewer_and_viewed_info'] = isset($filters['viewer_and_viewed_info'])? $filters['viewer_and_viewed_info'] : $this->getInfoAboutViewerAndViewed($account_info, $filters);
  1247. $filters['edmodo_messages_only'] = isset($filters['edmodo_messages_only'])? $filters['edmodo_messages_only'] : false;
  1248. $filters['message_id_upper_bound'] = isset($filters['message_id_upper_bound'])? $filters['message_id_upper_bound'] : false;
  1249. self::initializeTranslators($language);
  1250. $viewer_and_viewed_info = $filters['viewer_and_viewed_info'];
  1251. $viewer_id = $viewer_and_viewed_info['viewer_id'];
  1252. $viewer_type = $viewer_and_viewed_info['viewer_type'];
  1253. $viewed_user_info = $viewer_and_viewed_info['viewed_user_info'];
  1254. $viewed_user_group_ids = $viewer_and_viewed_info['viewed_user_group_ids'];
  1255. $viewed_taught_groups = $viewer_and_viewed_info['viewed_taught_groups'];
  1256. $messages_model = Messages::getInstance();
  1257. switch($this->feed_type){
  1258. case 'COMMUNITY_FEED':
  1259. if($filters['trending_posts']){
  1260. $messages = $messages_model->getCommunityTrendingMessages($filters);
  1261. }else{
  1262. $messages = $messages_model->getCommunityMessages($filters);
  1263. if( count($messages) && ($this->community_user_status == ADMINS || $this->community_user_status == FOLLOWS_CAN_POST || $this->community_user_status == FOLLOWS_CANT_POST ) ){
  1264. SubjectCommunityHandler::getInstance()->updateLastSeenMessageId($viewer_id, $filters['community_id'], $messages[0]['message_id']);
  1265. }
  1266. }
  1267. break;
  1268. case 'SCHOOL_FEED':
  1269. $messages = $messages_model->getInstitutionMessages($account_info, $filters, $this->institutional_info, 'SCHOOL');
  1270. break;
  1271. case 'DISTRICT_FEED':
  1272. $messages = $messages_model->getInstitutionMessages($account_info, $filters, $this->institutional_info, 'DISTRICT');
  1273. break;
  1274. default:
  1275. $messages = $messages_model->getEdmodoMessages($account_info, $filters, $viewed_user_group_ids, $this->institutional_info);
  1276. break;
  1277. }
  1278. // if edmodo_messages_only option is set, return messages here
  1279. if ($filters['edmodo_messages_only']) {
  1280. return $messages;
  1281. }
  1282. $messages = $this->getMissingMessageInfos($messages, $library_button);
  1283. $all_messages = array();
  1284. $all_ids = array();
  1285. $msg_count = count($messages);
  1286. $poll_ids = array();
  1287. $assignment_ids = array();
  1288. $link_ids = array();
  1289. $file_ids = array();
  1290. $final_msg_count = 0;
  1291. $embed_ids = array();
  1292. $comment_ids = array();
  1293. $quiz_ids = array();
  1294. $app_message_ids = array();
  1295. if ($viewer_type == USERS::TYPE_STUDENT) {
  1296. $teacher_ids = Users::getInstance()->getTeacherIdsFromUserGroups($viewer_id);
  1297. } else {
  1298. $teacher_ids = array();
  1299. }
  1300. for($i = 0; $i < $msg_count;){
  1301. $message = $messages[$i];
  1302. //Notice the $i is passed by reference to the next function and will be modified there
  1303. $message = $this->extractMessageReceivers($messages, $i, $language, $viewer_id, $viewer_type, $viewed_taught_groups, $filters, $teacher_ids);
  1304. $this->processMessageInfo($message, $language);
  1305. if (isset($message['posted_in'])) {
  1306. if ($message['posted_in'] == 'connections') {
  1307. $message['sent_to_connections'] = 1;
  1308. }
  1309. }
  1310. /* Show Library Button if Community Post */
  1311. if ($message['sent_to_community'] || (isset($message['sent_to_connections']) && $message['sent_to_connections']) || $message['sender_type'] == 'ADMINISTRATOR') {
  1312. $message['add-to-library'] = 1;
  1313. }
  1314. /* Don't show Library Button if viewer = creator */
  1315. if ($message['creator_id'] == $viewer_id) {
  1316. if (isset($message['add-to-library'])) {
  1317. unset($message['add-to-library']);
  1318. $message['library-items-by-me'] = 1;
  1319. }
  1320. } else if ($message['sender_type'] == 'ADMINISTRATOR') {
  1321. unset($message['add-to-library']);
  1322. }
  1323. switch( $message['type'] ){
  1324. case 'text':
  1325. $file_ids[$message['message_id']] = $final_msg_count;
  1326. $embed_ids[$message['message_id']] = $final_msg_count;
  1327. $link_ids[$message['message_id']] = $final_msg_count;
  1328. $message['files'] = array();
  1329. $message['embeds'] = array();
  1330. $message['links'] = array();
  1331. break;
  1332. case 'link':
  1333. case 'video':
  1334. // Store the message id and the index in the messages array for later
  1335. $link_ids[$message['message_id']] = $final_msg_count;
  1336. break;
  1337. case 'file':
  1338. $file_ids[$message['message_id']] = $final_msg_count;
  1339. $message['files'] = array();
  1340. break;
  1341. case 'embed':
  1342. // Store the message id and the index in the messages array for later
  1343. $embed_ids[$message['message_id']] = $final_msg_count;
  1344. break;
  1345. case ASSIGNMENT:
  1346. $file_ids[$message['message_id']] = $final_msg_count;
  1347. $message['files'] = array();
  1348. if (UNIFIED_POST_TYPES) {
  1349. $embed_ids[$message['message_id']] = $final_msg_count;
  1350. $link_ids[$message['message_id']] = $final_msg_count;
  1351. $message['embeds'] = array();
  1352. $message['links'] = array();
  1353. }
  1354. $assignment_ids[ $message['message_id'] ] = $final_msg_count;
  1355. break;
  1356. case 'feed':
  1357. // Store the message id and the index in the messages array for later
  1358. $link_ids[$message['message_id']] = $final_msg_count;
  1359. $message['sender_thumb'] = PATH2_IMAGES . 'rss.png';
  1360. // NEED new/larger RSS icon, will use small on for now:
  1361. $message['sender_full_avatar'] = PATH2_IMAGES . 'rss.png';
  1362. break;
  1363. case 'poll':
  1364. $poll_ids[ $message['message_id'] ] = $final_msg_count;
  1365. break;
  1366. case 'quiz':
  1367. $quiz_ids[ $message['message_id'] ] = $final_msg_count;
  1368. $message['edit_rights'] = false;
  1369. break;
  1370. case MessagingHelper::MESSAGE_TYPE_APP_MESSAGE:
  1371. $app_message_ids[ $message['message_id'] ] = $final_msg_count;
  1372. break;
  1373. }
  1374. $all_ids[ $message['message_id'] ] = $final_msg_count;
  1375. $message['tags'] = array();
  1376. $message['comment_count'] = 0;
  1377. $all_messages[] = $message;
  1378. $final_msg_count++;
  1379. }
  1380. $user_id = '';
  1381. $account_info = AccountHandler::getInstance()->getAccountInfo();
  1382. if ($account_info)
  1383. {
  1384. $user_id = $account_info['user_id'];
  1385. }
  1386. $all_messages = EmbedHandler::getInstance()->processEmbeds($all_messages, $embed_ids, 'MESSAGE', $user_id);
  1387. $all_messages = LinkHandler::getInstance()->processLinks($all_messages, $link_ids, 'MESSAGE', $user_id);
  1388. $all_messages = FileHandler::getInstance()->processFiles($all_messages, $file_ids, 'MESSAGE', $user_id);
  1389. $all_messages = AssignmentHandler::getInstance()->processAssignments($all_messages, $assignment_ids, $viewer_id, $viewed_taught_groups, $language);
  1390. $all_messages = QuizHandler::getInstance()->processQuizzes($all_messages, $quiz_ids, $viewer_id, $viewed_taught_groups, $language);
  1391. $all_messages = PollHandler::getInstance()->processPolls($all_messages, $poll_ids, $viewer_id, $viewer_type);
  1392. if ($app_message_ids) {
  1393. // process app messages
  1394. $all_messages = AppsMessagesHandler::getInstance()->processAppMessages($all_messages, $app_message_ids, $user_id);
  1395. }
  1396. $all_messages = ReactionsHandler::getInstance()->processReactions($all_messages, $all_ids, $user_id);
  1397. if( !$filters['public_only'] || $filters['community_id'] != null ){
  1398. $all_messages = TagHandler::getInstance()->processTags($all_messages, $all_ids, $viewer_id, $language, $filters['community_id']);
  1399. }
  1400. if ( $filters['include_comments'] ){
  1401. $all_messages = $this->processComments($all_messages, $all_ids, $language, $viewer_id, $viewer_type, $filters);
  1402. }
  1403. if(count($all_messages)){
  1404. if(!empty($viewer_id) && isset($viewed_user_info['type']) && $viewed_user_info['type'] == 'PUBLISHER'){
  1405. //Update the last seen message for this publisher/user pair
  1406. PublisherNewMessages::getInstance()->updatePublisherLastSeenMessageId($viewer_id, $viewed_user_info['user_id'], $all_messages[0]['message_id']);
  1407. }
  1408. if($this->feed_type == 'HOME_FEED' && $viewer_type == 'TEACHER'){
  1409. //update the last seen message for this community/user
  1410. $communities = array();
  1411. $publishers = array();
  1412. foreach($all_messages as $message){
  1413. if($message['type'] != 'comment'){
  1414. foreach($message['receivers'] as $receiver){
  1415. if($receiver['type'] == 'community' && !in_array($receiver['id'], $communities)){
  1416. SubjectCommunityHandler::getInstance()->updateLastSeenMessageId($viewer_id, $receiver['id'], $message['message_id']);
  1417. $communities[] = $receiver['id'];
  1418. break;
  1419. }else if(isset($receiver['user_type']) && $receiver['user_type'] == 'PUBLISHER' && !in_array($receiver['id'], $publishers)){
  1420. PublisherNewMessages::getInstance()->updatePublisherLastSeenMessageId($viewer_id, $receiver['id'], $message['message_id']);
  1421. $publishers[] = $receiver['id'];
  1422. break;
  1423. }
  1424. }
  1425. }
  1426. }
  1427. }
  1428. }
  1429. return $all_messages;
  1430. }
  1431. private function getInfoAboutViewerAndViewed(&$account_info, &$filters)
  1432. {
  1433. $viewer_id = 0;
  1434. $viewer_type = 'STUDENT';
  1435. $viewed_user_info = null;
  1436. $viewed_taught_groups = array();
  1437. if(isset($account_info)){
  1438. $viewer_id = $account_info['user_id'];
  1439. $viewer_type = $account_info['type'];
  1440. $viewed_user_info = $account_info;
  1441. if ( $filters['user_feed_id'] ){
  1442. if($filters['people_filter'] == 'STUDENT'){
  1443. //Parent viewing one of his students
  1444. $filters['student_id'] = $filters['user_feed_id'];
  1445. }
  1446. else{
  1447. $user_info = Users::getInstance()->find($filters['user_feed_id']);
  1448. if ( $account_info['type'] == 'ADMINISTRATOR' || $user_info['type'] == 'PUBLISHER' ){
  1449. $viewed_user_info = $account_info = $user_info;
  1450. }
  1451. }
  1452. }
  1453. elseif ( $filters['sender_id'] && $account_info['type'] == 'PARENT' ){
  1454. $viewed_user_info = $user_info = Users::getInstance()->find($filters['sender_id']);
  1455. }
  1456. } elseif ($filters['user_feed_id']) {
  1457. $user_info = Users::getInstance()->find($filters['user_feed_id']);
  1458. if ($user_info['type'] == 'PUBLISHER'){
  1459. $viewed_user_info = $account_info = $user_info;
  1460. }
  1461. }
  1462. if ( !empty($filters['community_id']) ){
  1463. $this->community_user_status = SubjectCommunities::getInstance()->getUserStatus($account_info, $filters['community_id']);
  1464. }
  1465. switch($viewer_type){
  1466. case 'STUDENT':
  1467. case 'TEACHER':
  1468. case 'PUBLISHER':
  1469. case 'ADMINISTRATOR':
  1470. if ( $viewer_type == 'ADMINISTRATOR' ){
  1471. $this->institutional_info = InstitutionalHandler::getInstance()->getInstitutionalInfo($viewed_user_info, $this->feed_type);
  1472. }
  1473. if(isset($viewed_user_info)){
  1474. $this->institutional_info = InstitutionalHandler::getInstance()->getInstitutionalInfo($viewed_user_info, $this->feed_type);
  1475. //-------------------------
  1476. // Get the groups that the user being viewed belongs to
  1477. $include_archived = false;
  1478. if($filters['tag_id'] != null){
  1479. $include_archived = true;
  1480. }
  1481. $viewed_user_groups_info = GroupsHandler::getInstance()->getUsersGroupsInfo($viewed_user_info['user_id'],$include_archived);
  1482. $this->viewed_user_groups = $viewed_user_groups_info['groups'];
  1483. $filters['archived_group_ids'] = $viewed_user_groups_info['archived_group_ids'];
  1484. $group_ids = array();
  1485. foreach( $viewed_user_groups_info['groups'] as $group ){
  1486. array_push($group_ids,$group['group_id']);
  1487. if( $viewer_type == 'TEACHER' ){
  1488. if( $group['user_owns_group'] == 1 || $group['co_teacher'] == 1){
  1489. $viewed_taught_groups[$group['group_id']] = true;
  1490. }
  1491. }
  1492. }
  1493. }
  1494. $this->parent_info['parents'] = $filters['parents'];
  1495. break;
  1496. case 'PARENT':
  1497. $this->parent_info['students_info_for_parent'] = $filters['students_info_for_parent'];
  1498. break;
  1499. }
  1500. if(empty($this->viewed_user_id) && !empty($viewed_user_info)){
  1501. $this->viewed_user_id = $viewed_user_info['user_id'];
  1502. }
  1503. $viewed_user_group_ids = isset($viewed_user_groups_info['groups_ids'])? $viewed_user_groups_info['groups_ids'] : array();
  1504. $viewer_and_viewed_info = array(
  1505. 'viewer_id' => $viewer_id,
  1506. 'viewer_type' => $viewer_type,
  1507. 'viewed_user_info' => $viewed_user_info,
  1508. 'viewed_user_group_ids' => $viewed_user_group_ids,
  1509. 'viewed_taught_groups' => $viewed_taught_groups
  1510. );
  1511. return $viewer_and_viewed_info;
  1512. }
  1513. /*
  1514. Get additional information for the messages about: sender, recipients, avatar thumbs, etc.
  1515. */
  1516. private function getMissingMessageInfos($messages, $library_button){
  1517. // -------------------------
  1518. // Fill data from memcache
  1519. $message_data_ids = Array();
  1520. $user_ids = Array();
  1521. for ($i = 0; $i < count($messages); $i++) {
  1522. // Message content
  1523. $message_data_ids[] = $messages[$i]['message_id'];
  1524. // Receiver user
  1525. if ($messages[$i]['posted_in'] == 'user') {
  1526. $user_ids[] = $messages[$i]['posted_in_id'];
  1527. }
  1528. $user_ids[] = $messages[$i]['creator_id'];
  1529. }
  1530. $profiles = Profiles::getInstance();
  1531. $message_data = MessageData::getInstance();
  1532. $users = Users::getInstance();
  1533. $matched_profiles = $profiles->find($user_ids);
  1534. $matched_message_data = $message_data->find($message_data_ids)->toArray();
  1535. $matched_users = $users->find($user_ids);
  1536. // get the comments last updated timestamp for the messages
  1537. $comments_last_updated_timestamp_by_message_id_array = NewComments::getInstance()->getLatestCommentTimestampForMessage($message_data_ids);
  1538. for ($i = 0; $i < count($messages); $i++){
  1539. // Users
  1540. $matched_user = null;
  1541. foreach ($matched_users as $user) {
  1542. if ($user['user_id'] == $messages[$i]['creator_id']) {
  1543. $messages[$i]['sender_first_name'] = $user['first_name'];
  1544. $messages[$i]['sender_last_name'] = $user['last_name'];
  1545. $messages[$i]['sender_type'] = $user['type'];
  1546. if ($user['type'] == 'PUBLISHER') {
  1547. $messages[$i]['sent_to_community'] = true;
  1548. }
  1549. $messages[$i]['sender_title'] = $user['title'];
  1550. $matched_user = $user;
  1551. break;
  1552. }
  1553. }
  1554. // Thumbnails
  1555. foreach ($matched_profiles as $profile)
  1556. {
  1557. if ($profile->user_id == $messages[$i]['creator_id'] && !is_null($matched_user))
  1558. {
  1559. $messages[$i]['sender_thumb'] = $profiles->getAvatarUrlFromProfile($profile, $matched_user['username'], 'THUMB');
  1560. $messages[$i]['sender_full_avatar'] = $profiles->getAvatarUrlFromProfile($profile, $matched_user['username'], '');
  1561. $messages[$i]['secondary_theme_enabled'] = $profile['secondary_theme_enabled'];
  1562. break;
  1563. }
  1564. }
  1565. // Receivers
  1566. $messages[$i]['receiver_first_name'] = null;
  1567. $messages[$i]['receiver_last_name'] = null;
  1568. $messages[$i]['receiver_type'] = null;
  1569. $messages[$i]['receiver_title'] = null;
  1570. if ($messages[$i]['posted_in'] == 'user') {
  1571. foreach ($matched_users as $user) {
  1572. if ($user['user_id'] == $messages[$i]['posted_in_id']) {
  1573. $messages[$i]['receiver_first_name'] = $user['first_name'];
  1574. $messages[$i]['receiver_last_name'] = $user['last_name'];
  1575. $messages[$i]['receiver_type'] = $user['type'];
  1576. $messages[$i]['receiver_title'] = $user['title'];
  1577. break;
  1578. }
  1579. }
  1580. }
  1581. // Message_data
  1582. foreach ($matched_message_data as $md) {
  1583. if ($md['message_id'] == $messages[$i]['message_id']) {
  1584. $messages[$i]['content'] = $md['content'];
  1585. $messages[$i]['last_updated'] = $md['last_updated'];
  1586. if ($library_button) {
  1587. $messages[$i]['add-to-library'] = 1;
  1588. }
  1589. break;
  1590. }
  1591. }
  1592. // set last_updated_ts
  1593. $messages[$i]['last_updated_ts'] = strtotime($messages[$i]['last_updated'] . ' ' . DATABASE_TIMEZONE_IDENTIFIER);
  1594. // Comments last updated for message (-1 signifies there are no comments for this message)
  1595. if (isset($comments_last_updated_timestamp_by_message_id_array[$messages[$i]['message_id']])
  1596. && $comments_last_updated_timestamp_by_message_id_array[$messages[$i]['message_id']] != -1
  1597. ) {
  1598. $messages[$i]['comments_last_updated_ts'] = $comments_last_updated_timestamp_by_message_id_array[$messages[$i]['message_id']];
  1599. } else {
  1600. $messages[$i]['comments_last_updated_ts'] = null;
  1601. }
  1602. }
  1603. return $messages;
  1604. } //getMissingMessageInfos
  1605. /**
  1606. * Formats a message
  1607. * @param array $message
  1608. * @param string language viewing user's language
  1609. */
  1610. public function processMessageInfo(&$message, $language)
  1611. {
  1612. if($message['type'] == 'system'){
  1613. $this->processSystemMessage($message, $language);
  1614. }
  1615. else
  1616. {
  1617. // only perform data string formatting if this is not an API call
  1618. $message['content'] = MessagingHelper::formatDBString($message['content'], true, $message['creator_id'] != EDMODO_SYSTEM_USER_ID, $message['type'] == 'comment');
  1619. }
  1620. $message['formal_creation_date'] = date(DATE_RSS, strtotime($message['creation_date']));
  1621. $message['creation_date'] = DateTimeHelper::getInstance($language)->formatCreationDate( $message['creation_date'] );
  1622. if($message['sent'] && $language == 'en'){
  1623. //This user sent the message (only translated if it's english to 'Me', for now)
  1624. $message['sender_name'] = 'Me';
  1625. }else{
  1626. $sender = array('first_name' => $message['sender_first_name'],
  1627. 'last_name' => $message['sender_last_name'],
  1628. 'type' => $message['sender_type'],
  1629. 'title' => $message['sender_title']
  1630. );
  1631. if( !isset($message['sender_name']) )
  1632. {
  1633. $message['sender_name'] = self::formatName($sender, $language);
  1634. }
  1635. }
  1636. $message['sender_representative'] = 'none';
  1637. if ($message['sender_type'] == 'TEACHER') {
  1638. $representative = RepresentativeUsers::getInstance()->getRepresentativeUser($message['creator_id']);
  1639. if (!empty($representative)) {
  1640. $message['sender_representative'] = $representative['privilege_level'];
  1641. }
  1642. }
  1643. if ( $message['sender_type'] == 'ADMINISTRATOR' ){
  1644. $administered_entity_info = Users::getInstance()->getAdministeredEntityInfo($message['creator_id']);
  1645. $message['administered_entity'] = $administered_entity_info['entity_name'];
  1646. $message['administered_entity_community_name'] = $administered_entity_info['entity_community_name'];
  1647. $message['administered_entity_type'] = $administered_entity_info['entity_type'];
  1648. }
  1649. //initialize a sender_and_receivers string
  1650. $message['sender_and_receivers'] = '';
  1651. //initialize the link to the avatar
  1652. if ( $message['sender_type'] == 'TEACHER' || $message['sender_type'] == 'PARENT' )
  1653. {
  1654. $message['avatar_link'] = '/profile/' . $message['creator_id'];
  1655. }
  1656. elseif( $message['sender_type'] == 'PUBLISHER' ){
  1657. $message['avatar_link'] = '/publisher?uid=' . $message['creator_id'];
  1658. }
  1659. elseif($message['sender_type'] == 'ADMINISTRATOR'){
  1660. $message['avatar_link'] = '/'.$message['administered_entity_type'].'/'.$message['administered_entity_community_name'];
  1661. }
  1662. elseif($message['sender_type'] === 'STUDENT'){
  1663. $message['avatar_link'] = '/user?uid=' . $message['creator_id'];
  1664. }
  1665. }
  1666. /**
  1667. * Prepares a string extracted from the DB for display
  1668. * Optionally escapes all html characters and quotes
  1669. * Inserts <p>...</p> tags instead of newlines
  1670. * Special format for STORE - PUBLISHER description
  1671. * Optionally changes all link appearances to html anchor tags (ie: 'http://www.yahoo.com' to '<a href="http://www.yahoo.com">http://www.yahoo.com</a>')
  1672. * @param string $data the string to modify
  1673. * @param bool $replace_links_with_anchors whether to change links to anchor tags
  1674. * @param bool $escape whether to escape special html characters
  1675. * @param bool $remove_newlines
  1676. * @param bool $nl2p
  1677. * @return modified string
  1678. */
  1679. public static function formatDBStringForStore($data, $replace_links_with_anchors, $escape=true, $remove_newlines=false, $nl2p=true){
  1680. // omit formatting of data for api calls
  1681. if (self::$is_api_call)
  1682. {
  1683. return $data;
  1684. }
  1685. $domain = ArrayHelper::elem($data, 'domain', SystemHelper::getDomain());
  1686. if($replace_links_with_anchors){
  1687. // get math expressions before escaping
  1688. $thunks = array();
  1689. preg_match_all('/\[math\](.*?)\[\/math\]/si', $data, $matches);
  1690. for ($i=0; $i < count($matches[0]); $i++) {
  1691. $position = strpos($data, $matches[0][$i]);
  1692. $thunks[] = $matches[1][$i];
  1693. }
  1694. }
  1695. if( $escape ){
  1696. //escape the content
  1697. $data = htmlspecialchars($data, QUOTE_STYLE);
  1698. }
  1699. if($replace_links_with_anchors){
  1700. $data = "!$data!";
  1701. $data = str_replace("\nwww.", "\nhttp://www.", $data);
  1702. $data = str_replace(" www.", ' http://www.', $data);
  1703. $data = str_replace("!www.", ' http://www.', $data);
  1704. $data = str_replace("\nedmo.do/j/", "\nhttps://edmo.do/j/", $data);
  1705. $data = str_replace(" edmo.do/j/", " https://edmo.do/j/", $data);
  1706. $data = str_replace("!edmo.do/j/", " https://edmo.do/j/", $data);
  1707. $regexp = '/[[:alpha:]]+:\/\/[^<>[:space:]]+[[:alnum:]|\/|@][\.]?[ |\n|\r|!]/siU';
  1708. if( strlen($data) < 20000 ){
  1709. if(preg_match_all($regexp, $data, $matches, PREG_SET_ORDER)) {
  1710. foreach($matches as $match) {
  1711. $length = strlen($match[0]);
  1712. $url = substr($match[0], 0, $length-1);
  1713. $abb_url = $url;
  1714. $url = rtrim($url, ".");
  1715. if (strlen($abb_url) > 45) {
  1716. $abb_url = substr($abb_url, 0, 45)."...";
  1717. }
  1718. $ending = substr($match[0], $length-1, $length);
  1719. $data = str_replace($match[0], "<a class=\"word-wrap\" target=\"_blank\" href=\"".$url."\">$abb_url</a>$ending", $data);
  1720. }
  1721. }
  1722. }
  1723. $data = substr($data, 1, strlen($data)-2);
  1724. // replace math expressions
  1725. preg_match_all('/\[math\](.*?)\[\/math\]/si', $data, $matches);
  1726. for ($i=0; $i < count($matches[0]); $i++) {
  1727. $position = strpos($data, $matches[0][$i]);
  1728. $hash = md5($thunks[$i]);
  1729. $url = NEW_MATH_IMAGES_SERVER . "$hash.png";
  1730. $data = substr_replace($data, "<a href=\"$url\" rel=\"facebox\"><img src=\"$url\" /></a>", $position, strlen($matches[0][$i]));
  1731. }
  1732. }
  1733. if ( $remove_newlines ){
  1734. $data = preg_replace(array('/\r/m','/\n{2,}/m'), array("\n","\n"), $data);
  1735. }
  1736. else{
  1737. $data = preg_replace(array('/\r/m','/\n{3,}/m'), array("\n","\n\n"), $data);
  1738. }
  1739. //replace newlines with <br>
  1740. if ($nl2br){
  1741. $data = str_replace("\n", HTML_BREAK_TAG, $data);
  1742. }
  1743. //replace newlines with <p>
  1744. if ($nl2p){
  1745. $data = preg_replace('/\n(\s*\n)+/', '</p><p>', $data);
  1746. $data = preg_replace('/\n/', '<br>', $data);
  1747. //$data = '<p>'.$data.'</p>';
  1748. }
  1749. return $data;
  1750. }
  1751. /**
  1752. * Prepares a string extracted from the DB for display
  1753. * Optionally escapes all html characters and quotes
  1754. * Inserts <br> tags instead of newlines
  1755. * Optionally changes all link appearances to html anchor tags (ie: 'http://www.yahoo.com' to '<a href="http://www.yahoo.com">http://www.yahoo.com</a>')
  1756. * @param string $data the string to modify
  1757. * @param bool $replace_links_with_anchors whether to change links to anchor tags
  1758. * @param bool $escape whether to escape special html characters
  1759. * @return modified string
  1760. */
  1761. public static function formatDBString($data, $replace_links_with_anchors, $escape=true, $remove_newlines=false, $nl2br=true){
  1762. // omit formatting of data for api calls
  1763. if (self::$is_api_call)
  1764. {
  1765. return $data;
  1766. }
  1767. $domain = ArrayHelper::elem($data, 'domain', SystemHelper::getDomain());
  1768. if($replace_links_with_anchors){
  1769. // get math expressions before escaping
  1770. $thunks = array();
  1771. preg_match_all('/\[math\](.*?)\[\/math\]/si', $data, $matches);
  1772. for ($i=0; $i < count($matches[0]); $i++) {
  1773. $position = strpos($data, $matches[0][$i]);
  1774. $thunks[] = $matches[1][$i];
  1775. }
  1776. }
  1777. if( $escape ){
  1778. //escape the content
  1779. $data = htmlspecialchars($data, QUOTE_STYLE);
  1780. }
  1781. if($replace_links_with_anchors){
  1782. $data = "!$data!";
  1783. $data = str_replace("\nwww.", "\nhttp://www.", $data);
  1784. $data = str_replace(" www.", ' http://www.', $data);
  1785. $data = str_replace("!www.", ' http://www.', $data);
  1786. $data = str_replace("\nedmo.do/j/", "\nhttps://edmo.do/j/", $data);
  1787. $data = str_replace(" edmo.do/j/", " https://edmo.do/j/", $data);
  1788. $data = str_replace("!edmo.do/j/", " https://edmo.do/j/", $data);
  1789. $regexp = '/[[:alpha:]]+:\/\/[^<>[:space:]]+[[:alnum:]|\/|@][\.]?[ |\n|\r|!]/siU';
  1790. if( strlen($data) < 20000 ){
  1791. if(preg_match_all($regexp, $data, $matches, PREG_SET_ORDER)) {
  1792. foreach($matches as $match) {
  1793. $length = strlen($match[0]);
  1794. $url = substr($match[0], 0, $length-1);
  1795. $abb_url = $url;
  1796. $url = rtrim($url, ".");
  1797. if (strlen($abb_url) > 45) {
  1798. $abb_url = substr($abb_url, 0, 45)."...";
  1799. }
  1800. $ending = substr($match[0], $length-1, $length);
  1801. $data = str_replace($match[0], "<a class=\"word-wrap\" target=\"_blank\" href=\"".$url."\">$abb_url</a>$ending", $data);
  1802. }
  1803. }
  1804. }
  1805. $data = substr($data, 1, strlen($data)-2);
  1806. // replace math expressions
  1807. preg_match_all('/\[math\](.*?)\[\/math\]/si', $data, $matches);
  1808. for ($i=0; $i < count($matches[0]); $i++) {
  1809. $position = strpos($data, $matches[0][$i]);
  1810. $hash = md5($thunks[$i]);
  1811. $url = NEW_MATH_IMAGES_SERVER . "$hash.png";
  1812. $data = substr_replace($data, "<a href=\"$url\" rel=\"facebox\"><img src=\"$url\" /></a>", $position, strlen($matches[0][$i]));
  1813. }
  1814. }
  1815. if ( $remove_newlines ){
  1816. $data = preg_replace(array('/\r/m','/\n{2,}/m'), array("\n","\n"), $data);
  1817. }
  1818. else{
  1819. $data = preg_replace(array('/\r/m','/\n{3,}/m'), array("\n","\n\n"), $data);
  1820. }
  1821. //replace newlines with <br>
  1822. if ($nl2br){
  1823. $data = str_replace("\n", HTML_BREAK_TAG, $data);
  1824. }
  1825. return $data;
  1826. }
  1827. /**
  1828. * Formats a system message
  1829. * @param array $message
  1830. */
  1831. private function processSystemMessage(&$message, $language){
  1832. // translate the system message to the user's language
  1833. $content_array = explode(':', $message['content']);
  1834. $account_info = AccountHandler::getInstance()->getAccountInfo();
  1835. // The first element is the system message identifier
  1836. $identifier = $content_array[0];
  1837. // Get the teacher name (used for the Teacher's Profile Feed messages)
  1838. $teacher_name = '';
  1839. $teacher_id = 0;
  1840. switch($identifier){
  1841. // New group system message
  1842. // Expected message content:
  1843. // new-group:group_id
  1844. case 'new-group':
  1845. $group_id = $content_array[1];
  1846. $group_info = Groups::getInstance()->getGroup($group_id);
  1847. $message['content'] = '';
  1848. if( !empty($group_info) ){
  1849. $message['content'] = self::$system_msgs_translator->_($identifier, $group_info['title'], $group_info['code']);
  1850. }
  1851. break;
  1852. // Teacher joined group system message
  1853. // Expected message content:
  1854. // teacher-joined-group:group_id-user_id
  1855. case 'teacher-joined-group':
  1856. $join_info = explode('-', $content_array[1]);
  1857. $group_info = Groups::getInstance()->getGroup($join_info[0]);
  1858. $message['content'] = self::$system_msgs_translator->_($identifier, $group_info['title']);
  1859. break;
  1860. case 'new-user':
  1861. $account_info = AccountHandler::getInstance()->getAccountInfo();
  1862. if( isset($account_info['type']) && $account_info['type'] == 'TEACHER' )
  1863. if(USE_NEW_USER_XP){
  1864. $should_see_welcome_message = AbHandler::idInTest($account_info['user_id'], 'checklist_entry_point') == 'stream' ? true : false;
  1865. $should_see_welcome_message = true;
  1866. if ($should_see_welcome_message){
  1867. ActionsTracking::getInstance()->insert(array(
  1868. ActionsTrackingConstants::USER_AGENT => getenv('HTTP_USER_AGENT'),
  1869. ActionsTrackingConstants::EVENT_TYPE => 'stream-get-started-message',
  1870. ActionsTrackingConstants::USER_ID => $account_info['user_id'],
  1871. ));
  1872. $message['content'] = self::$system_msgs_translator->_('get-started-alt','<br>','<a href="/get-started">', '</a>');
  1873. }
  1874. else{
  1875. $message['content'] = self::$system_msgs_translator->_('new-teacher-alt', '<br>', '<a id="system-group-create" a="Create group from system message clicked." href="javascript:;">', '</a>');
  1876. }
  1877. }
  1878. else
  1879. $message['content'] = self::$system_msgs_translator->_('new-teacher', '<br>');
  1880. else if (isset($account_info['type']) && $account_info['type'] == 'STUDENT')
  1881. $message['content'] = self::$system_msgs_translator->_('new-student');
  1882. else
  1883. $message['content'] = self::$system_msgs_translator->_('new-user', '<br>');
  1884. break;
  1885. // User has been added to a Small Group
  1886. // Expected message content:
  1887. // added-to-small-group:group_id
  1888. case 'added-to-small-group':
  1889. $group_info = Groups::getInstance()->getGroup( $content_array[1], false, true );
  1890. $group_title = $group_info['title'];
  1891. if (isset($group_info['parent_group_title'])){
  1892. $group_title = $group_info['title'] . ' (' . $group_info['parent_group_title'] .')';
  1893. }
  1894. if(count($message['receivers']) == 1 && $message['receivers'][0]['id'] == $account_info['user_id'] )
  1895. {
  1896. $message['content'] = self::$system_msgs_translator->_('you-joined-small-group', $group_title);
  1897. }
  1898. else{
  1899. $message['content'] = self::$system_msgs_translator->_('user-joined-group', $group_title);
  1900. }
  1901. break;
  1902. default:
  1903. $message['content'] = self::$system_msgs_translator->_($identifier);
  1904. break;
  1905. }
  1906. }
  1907. /**
  1908. * Formats a user's name (e.g. Mr. Jimenez if it's a teacher, Diego J. if it's a student)
  1909. * @param array $user is the array with a user's info
  1910. * @param string $language is the viewing user's language
  1911. * @param bool $abbreviated whether to display student names as 'Diego J.' or 'Diego Jimenez'
  1912. * @param bool $show_teacher_first whether to display teacher's first name with their title
  1913. * return string $name with the formatted name
  1914. */
  1915. public static function formatName($user, $language, $abbreviated = true, $show_teacher_first = false){
  1916. $name = '';
  1917. if(isset($user['type']) && ($user['type'] == 'TEACHER' || $user['type'] == 'ADMINISTRATOR') && $user['title'] != 'NONE'){
  1918. $first = '';
  1919. if ($show_teacher_first) {
  1920. $first = $user['first_name'].' ';
  1921. }
  1922. self::initializeTranslators($language);
  1923. // only call translator if there is actually a title
  1924. if (trim($user['title']) != '') {
  1925. $translated_title = self::$layout_translator->_($user['title']);
  1926. } else {
  1927. $translated_title = '';
  1928. }
  1929. // Title is added
  1930. if ( $language != 'zh' ){
  1931. $name = $translated_title . ' ' . ucwords($first.$user['last_name']);
  1932. }
  1933. else{
  1934. $name = ucwords($first.$user['last_name']) . $translated_title;
  1935. }
  1936. }else{
  1937. if (isset($user['type']) && $user['type'] == 'PUBLISHER'){
  1938. $name = $user['first_name'];
  1939. }elseif($abbreviated && isset($user['type']) && $user['type'] == 'STUDENT'){
  1940. // if mbstring extension is installed, use it to handle multibyte strings
  1941. if (function_exists('mb_substr')) {
  1942. $last_initial = mb_substr($user['last_name'], 0, 1, 'UTF-8');
  1943. } else {
  1944. $last_initial = substr($user['last_name'], 0, 1);
  1945. }
  1946. $name = $user['first_name'] . ' ' . $last_initial . '.';
  1947. }else{
  1948. $name = ucwords($user['first_name'].' '.$user['last_name']);
  1949. }
  1950. }
  1951. return $name;
  1952. }
  1953. /**
  1954. * Formats a parents's name (e.g. "Charles Li (Dad of Galen Li)")
  1955. * @param array $parent_info is the array with a parent's info
  1956. * @param array $student_info is the array with a student's info
  1957. * @param string $relation is the relationship between the student and the parent ('MOM', 'DAD', 'OTHER')
  1958. * @param string $language is the viewing user's language
  1959. * return string $parent_name with the formatted name
  1960. */
  1961. public static function formatParentName($parent_info, $student_info = null, $relation, $other_relation = null, $language, $viewer_type = 'TEACHER',$has_many_students = false)
  1962. {
  1963. self::initializeTranslators($language);
  1964. $translated_relation = ($relation == 'OTHER') ? $other_relation : self::$layout_translator->_($relation);
  1965. if($viewer_type == 'TEACHER')
  1966. {
  1967. $more_students = ($has_many_students) ? self::$layout_translator->_('and-more') : '';
  1968. $parent_name = self::$layout_translator->_('parent-name-as-teacher', $parent_info['first_name'], $parent_info['last_name'], $translated_relation, $student_info['first_name'], $student_info['last_name'],$more_students);
  1969. }
  1970. else
  1971. {
  1972. //student is viewer
  1973. $parent_name = self::$layout_translator->_('parent-name-as-student', $parent_info['first_name'], $parent_info['last_name'], $translated_relation);
  1974. }
  1975. return $parent_name;
  1976. }
  1977. /**
  1978. * Appends all receivers to a message.
  1979. * @param $messages is the array containing all the messages
  1980. * @param $pos is the position of the message in the $messages array.
  1981. * @param $language is the language used by the current user
  1982. * @param $viewer_id is the id of the current user
  1983. * @param $viewer_type is the type of the current user
  1984. * @param $taught_groups is a boolean flag of group_ids being taught by the user
  1985. */
  1986. private function extractMessageReceivers( &$messages, &$pos, $language, $viewer_id, $viewer_type, $taught_groups = array(),$filters = array(), $teacher_ids = array()){
  1987. $message = $messages[$pos];
  1988. $receivers = array();
  1989. $message_receiver = $message;
  1990. $message_count = count($messages);
  1991. $msg_submit_rights =
  1992. $msg_public_rights =
  1993. $msg_delete_rights =
  1994. $msg_hide_rights = false;
  1995. $msg_reply_rights = !empty($viewer_id) ? true : false;
  1996. $modified_rights = false;
  1997. $only_student_recipients = true;
  1998. $sent_to_community = false;
  1999. // $sent_to_connections = false;
  2000. $message['sent'] = ($viewer_id == $message['creator_id']);
  2001. while($message_receiver['message_id'] == $message['message_id'])
  2002. {
  2003. $full_receiver_info = $this->getMessageReceiverInfo($message_receiver, $language, $viewer_id, $viewer_type, $taught_groups, $filters);
  2004. if(isset($full_receiver_info))
  2005. {
  2006. //Add the receiver to the list
  2007. $rights = $full_receiver_info['rights'];
  2008. if(isset($rights['submit'])){
  2009. $msg_submit_rights = $rights['submit'];
  2010. }
  2011. if(isset($rights['public'])){
  2012. $msg_public_rights = true;
  2013. }
  2014. if(isset($rights['delete'])){
  2015. $msg_delete_rights = true;
  2016. }else if(isset($rights['hide'])){
  2017. $msg_hide_rights = true;
  2018. }
  2019. //if a user does not have permissions in one group might want to check the rest
  2020. if(isset($rights['reply']) && !$rights['reply'] && !$modified_rights){
  2021. $msg_reply_rights = false;
  2022. $modified_rights = true;
  2023. }
  2024. //if a user already has permissions to reply on this post, shouldnt overwrite it on the next while iteration
  2025. if(isset($rights['reply']) && $rights['reply']){
  2026. $msg_reply_rights = true;
  2027. $modified_rights = true;
  2028. }
  2029. if(isset($full_receiver_info['only_student_recipients']) && !$full_receiver_info['only_student_recipients']){
  2030. $only_student_recipients = false;
  2031. }
  2032. if(isset($full_receiver_info['sent_to_community'])){
  2033. $sent_to_community = true;
  2034. }
  2035. if(isset($rights['edit'])){
  2036. $msg_edit_rights = $rights['edit'];
  2037. }
  2038. $receivers[] = $full_receiver_info['receiver_info'];
  2039. // don't allow replies from students to teachers who are no longer their teacher via a group
  2040. if ($viewer_type == 'STUDENT') {
  2041. $teacher_receiver_ids = array();
  2042. foreach ($receivers as $receiver) {
  2043. if (!empty($receiver['user_type']) && $receiver['user_type'] == 'TEACHER') {
  2044. array_push($teacher_receiver_ids,$receiver['id']);
  2045. }
  2046. }
  2047. // check to see if at least one of the receivers is a teacher in one of the student's groups
  2048. if (count($teacher_receiver_ids) > 0) {
  2049. $is_active_teacher = count(array_uintersect($teacher_receiver_ids,$teacher_ids,'strcasecmp')) > 0 ? true : false;
  2050. $temp_reply_rights = $is_active_teacher;
  2051. } else {
  2052. $temp_reply_rights = true;
  2053. }
  2054. // check to see if sender is a teacher in one of the student's groups, otherwise no replies allowed
  2055. if ($message['sender_type'] == 'TEACHER' && !(count(array_uintersect(array($message['creator_id']),$teacher_ids,'strcasecmp')) > 0 ? true : false)) {
  2056. $temp_reply_rights = false;
  2057. }
  2058. if ($msg_reply_rights) {
  2059. $msg_reply_rights = $temp_reply_rights;
  2060. }
  2061. }
  2062. // change the variable $message to reference the next message in the list!
  2063. // this is needed to set the correct reciver to the original posted_in_id (for messages that are sent to multiple groups)
  2064. // so that a check of the user has access the a message will not break
  2065. $message = $messages[$pos];
  2066. $message['sent'] = ($viewer_id == $message['creator_id']); // re-set the 'sent' key
  2067. }
  2068. // The user can't see the recipient, shouldn't have other rights either
  2069. elseif ($viewer_type == 'STUDENT' && (
  2070. $message_receiver['posted_in'] == 'connections' ||
  2071. $message_receiver['posted_in'] == 'school' ||
  2072. $message_receiver['posted_in'] == 'school_vip' ||
  2073. $message_receiver['posted_in'] == 'school_parents' ||
  2074. $message_receiver['posted_in'] == 'district' ||
  2075. $message_receiver['posted_in'] == 'district_vip' ||
  2076. $message_receiver['posted_in'] == 'district_parents'
  2077. )
  2078. ) {
  2079. $msg_reply_rights = false;
  2080. }
  2081. //notice this affects the "parent" function behaviour
  2082. if (++$pos < $message_count) {
  2083. $message_receiver = $messages[$pos];
  2084. } else {
  2085. $message_receiver = array('message_id' => null);
  2086. }
  2087. }
  2088. $message['submit_rights'] = $msg_submit_rights;
  2089. unset($message['receiver_first_name'], $message['receiver_last_name'], $message['receiver_type'], $message['receiver_title']);
  2090. $message['public_rights'] = $msg_public_rights;
  2091. // $message["submit_rights"] = ArrayHelper::elem()
  2092. $message['delete_rights'] = ($message['sent'] && $this->feed_type != 'COMMUNITY_FEED'
  2093. && $this->feed_type != 'SCHOOL_FEED' && $this->feed_type != 'DISTRICT_FEED') || $msg_delete_rights;
  2094. $message['hide_rights'] = ($message['delete_rights']) ? false : $msg_hide_rights;
  2095. // This was mainly added for publishers,
  2096. // that's why if edit not set, we use the same "delete rights" which was previously used for this.
  2097. $message['edit_rights'] = (isset($msg_edit_rights)) ? $msg_edit_rights :$message['delete_rights'] ;
  2098. // Parents have no reply rights
  2099. $msg_reply_rights = ($viewer_type == 'PARENT') ? 0 : $msg_reply_rights;
  2100. //new condition to never let admins to reply on user_feed, be careful of when this filter comes on
  2101. $message['reply_rights'] = ($viewer_type == 'ADMINISTRATOR' && isset($filters['user_feed_id']) && !empty($filters['user_feed_id'])) ? 0 : $msg_reply_rights;
  2102. $message['only_student_recipients'] = $only_student_recipients;
  2103. if (!isset($message['sent_to_community']))
  2104. $message['sent_to_community'] = $sent_to_community;
  2105. $message['receivers'] = $receivers;
  2106. if($viewer_type == 'PARENT' && isset($this->parent_info['students_info_for_parent']['students'][$message['creator_id']]['hex'])){
  2107. $message['sender_color'] = $this->parent_info['students_info_for_parent']['students'][$message['creator_id']]['hex'];
  2108. }
  2109. return $message;
  2110. }
  2111. /**
  2112. * Gets required information on a message's receiver. For example, the name of a group where it was posted and its color
  2113. * @param $message_receiver the data of the receiver
  2114. * @param string $language viewing user's language
  2115. * @param int $viewer_id base user id for message retrieval
  2116. * @param string $viewer_type base user type for message retrieval
  2117. * @param array $taught_groups a boolean map of the ids of the groups taught by the user
  2118. * @return array $receiver_info contains the receiver's info. It is null if this receiver is not to be seen in the recipients list by the current user
  2119. */
  2120. private function getMessageReceiverInfo($message_receiver, $language, $viewer_id, $viewer_type, $taught_groups = array(),$filters = array() ){
  2121. $receiver_info = null;
  2122. $result = null;
  2123. $receiver_id = $message_receiver['posted_in_id'];
  2124. $receiver_info = array('type' => $message_receiver['posted_in'], 'id' => $receiver_id, 'receiver_name' => $message_receiver['posted_in'], 'receiver_color' => '#444444');
  2125. $rights = array();
  2126. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'recipients.tmx', $language);
  2127. switch($message_receiver['posted_in'])
  2128. {
  2129. case 'group':
  2130. case 'group_parents':
  2131. $group_data = array();
  2132. if( $this->feed_type == 'COMMUNITY_FEED' || $this->feed_type == 'SCHOOL_FEED' || $this->feed_type == 'DISTRICT_FEED' || $this->feed_type == 'POST_FEED' )
  2133. {
  2134. if ( isset($this->community_groups[$receiver_id]) ){
  2135. $group_data = $this->community_groups[$receiver_id];
  2136. }
  2137. else{
  2138. $group_data = Groups::getInstance()->getGroup($receiver_id, false);
  2139. $this->community_groups[$receiver_id] = $group_data;
  2140. if( !isset($this->viewed_user_groups[$receiver_id])){
  2141. $rights['reply'] = false;
  2142. }
  2143. else
  2144. {
  2145. $rights['reply'] = true;
  2146. }
  2147. }
  2148. if ( $this->community_user_status == ADMINS ){
  2149. $rights['delete'] = true;
  2150. }
  2151. if ($this->feed_type == 'SCHOOL_FEED' || $this->feed_type == 'DISTRICT_FEED'){
  2152. $rights['reply'] = false;
  2153. }
  2154. }
  2155. elseif( !empty($this->parent_info['students_info_for_parent']['students_groups_by_id'][$receiver_id]) )
  2156. {
  2157. //Parent feed
  2158. $group_data = $this->parent_info['students_info_for_parent']['students_groups_by_id'][$receiver_id];
  2159. //Change the title to include the children's names that belong to that group
  2160. if ( $message_receiver['posted_in'] == 'group_parents' ){
  2161. $group_data['title'] = $translator->_('group-parents', $group_data['title']);
  2162. }
  2163. else
  2164. {
  2165. //Parent can't reply to messages sent to their children only
  2166. $rights['reply'] = false;
  2167. }
  2168. $group_data['title'] = $this->addChildrensNames($group_data['title'], $group_data['student_ids']);
  2169. }
  2170. elseif( isset($this->viewed_user_groups[$receiver_id]) )
  2171. {
  2172. $group_data = $this->viewed_user_groups[$receiver_id];
  2173. if ( $message_receiver['posted_in'] == 'group_parents' ){
  2174. $group_data['title'] .= $translator->_('parents');
  2175. }
  2176. if(
  2177. ($group_data['read_only'] && !$group_data['is_small_group']) ||
  2178. ($group_data['main_read_only'] && $group_data['read_only'] && $group_data['is_small_group'] )
  2179. ){
  2180. //People with "read only" status can't reply to posts
  2181. $rights['reply'] = false;
  2182. }
  2183. }
  2184. if( count($group_data) ) // the message was sent to a group
  2185. {
  2186. //The viewed user belongs to this group
  2187. $receiver_info['receiver_name'] = $group_data['title'];
  2188. $receiver_info['group_creator_id'] = $group_data['creator_id'];
  2189. $receiver_info['moderated'] = $group_data['moderated'];
  2190. if( isset($group_data['hex']) ){
  2191. $receiver_info['receiver_color'] = $group_data['hex'];
  2192. }
  2193. $rights["submit"] = true; // Most users can submit/turn-in a submission for an assignment.
  2194. if( (
  2195. $receiver_info['group_creator_id'] == $viewer_id // Group-owner
  2196. && $this->feed_type != 'COMMUNITY_FEED' // & it's not a community feed.
  2197. )
  2198. || (isset( $taught_groups[$receiver_id] ) // OR the group-ID's in groups-taught list.
  2199. &&
  2200. ( ($taught_groups[$receiver_id] && ($message_receiver['creator_id'] == $viewer_id || $message_receiver['creator_id'] != $receiver_info['group_creator_id']))
  2201. || $message_receiver['sender_type'] != 'TEACHER'
  2202. || $message_receiver['creator_id'] == $viewer_id))
  2203. )
  2204. {
  2205. // This user created the group,
  2206. // he may make the message public and delete it
  2207. $rights['public'] = true;
  2208. $rights['delete'] = true;
  2209. $rights["submit"] = false; // A group-owner or co-teacher for the group cannot turn-in a submission.
  2210. }
  2211. // A STUDENT cannot edit a STUDENT's post if a group's moderated.
  2212. // Or in other words: they can't edit their own post under moderation.
  2213. if( $viewer_type == 'STUDENT'
  2214. && $message_receiver['sender_type'] == 'STUDENT'
  2215. && $group_data['moderated'] )
  2216. {
  2217. $rights['edit'] = false;
  2218. }
  2219. if( $viewer_type == 'ADMINISTRATOR'
  2220. && isset($filters['user_feed_id'])
  2221. && ! empty($filters['user_feed_id']) )
  2222. {
  2223. if($filters['user_feed_id'] == $message_receiver['creator_id'])
  2224. {
  2225. $rights['delete'] = true;
  2226. $rights['edit'] = false;
  2227. }
  2228. }
  2229. $result = array(
  2230. 'receiver_info' => $receiver_info,
  2231. 'rights' => $rights,
  2232. 'only_student_recipients' => false
  2233. );
  2234. }
  2235. break;
  2236. case 'user':
  2237. $recipient_name = '';
  2238. $format_name = true;
  2239. // Teachers can mark as public direct messages sent to or by them
  2240. if ( $viewer_type == 'TEACHER' && $viewer_id == $message_receiver['creator_id'] ){
  2241. $rights['public'] = true;
  2242. }
  2243. if($receiver_id == $viewer_id)
  2244. {
  2245. $rights['reply'] = true;
  2246. if($viewer_type == 'TEACHER'){
  2247. //teachers can delete any direct message they receive
  2248. $rights['delete'] = true;
  2249. $rights['public'] = true;
  2250. }
  2251. if($viewer_type == 'TEACHER' && $message_receiver['sender_type'] != 'STUDENT'){
  2252. $rights['edit'] = false;
  2253. }
  2254. if($viewer_type == 'PUBLISHER'){
  2255. $rights['delete'] = true;
  2256. $rights['edit'] = false;
  2257. }
  2258. if($language == 'en'){
  2259. //This recipient is 'me'
  2260. $recipient_name = self::$layout_translator->_('me');
  2261. $format_name = false;
  2262. }
  2263. }
  2264. elseif(isset($this->parent_info['parents'][$receiver_id]))
  2265. {
  2266. //It's a parent
  2267. $recipient_name = $this->parent_info['parents'][$receiver_id]['name'];
  2268. $format_name = false;
  2269. }
  2270. elseif( $message_receiver['receiver_type'] == 'PARENT' )
  2271. {
  2272. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2273. $parent_students = ParentsStudents::getInstance()->getStudentsInfo($receiver_id);
  2274. if(count($parent_students))
  2275. {
  2276. $has_many = (count($parent_students) > 1) ? true : false;
  2277. $a_student = Users::getInstance()->getUserInfo($parent_students[0]['student_id']) ;
  2278. $recipient = array('first_name' => $message_receiver['receiver_first_name'],
  2279. 'last_name' => $message_receiver['receiver_last_name'],
  2280. 'type' => $message_receiver['receiver_type'],
  2281. 'title' => $message_receiver['receiver_title']
  2282. );
  2283. $recipient_name = $this->formatParentName($recipient,$a_student,$parent_students[0]['relation'],$parent_students[0]['other_relation'],$language,'TEACHER',$has_many);
  2284. $format_name = false;
  2285. }
  2286. }
  2287. if($format_name)
  2288. {
  2289. //the message was sent directly to a person
  2290. $recipient = array('first_name' => $message_receiver['receiver_first_name'],
  2291. 'last_name' => $message_receiver['receiver_last_name'],
  2292. 'type' => $message_receiver['receiver_type'],
  2293. 'title' => $message_receiver['receiver_title']
  2294. );
  2295. $recipient_name = self::formatName($recipient, $language);
  2296. }
  2297. $only_student_recipients = false;
  2298. $sent_to_publisher = null;
  2299. switch ( $message_receiver['receiver_type'] ) {
  2300. case 'TEACHER':
  2301. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2302. break;
  2303. case 'PUBLISHER':
  2304. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2305. // Students can't reply to posts sent to publishers
  2306. if ( $viewer_type == 'STUDENT' ){
  2307. $rights['reply'] = false;
  2308. }
  2309. elseif ( $viewer_type == 'TEACHER' ) {
  2310. if ( !CoppaHandler::userIsCoppaVerified($viewer_id) ){
  2311. $rights['reply'] = false;
  2312. }
  2313. }
  2314. if( $this->feed_type == 'HOME_FEED' && $message_receiver['creator_id'] != $viewer_id){
  2315. //The user can hide this message
  2316. $rights['hide'] = true;
  2317. }
  2318. $sent_to_publisher = true;
  2319. break;
  2320. case 'STUDENT':
  2321. if($viewer_type == 'PARENT'){
  2322. if(isset($this->parent_info['students_info_for_parent']['students'][$receiver_id]['hex']))
  2323. {
  2324. $receiver_info['receiver_color'] = $this->parent_info['students_info_for_parent']['students'][$receiver_id]['hex'];
  2325. }
  2326. if($message_receiver['creator_id'] != $viewer_id){
  2327. //Parent can't reply
  2328. $rights['reply'] = false;
  2329. }
  2330. }
  2331. $only_student_recipients = true;
  2332. break;
  2333. }
  2334. $receiver_info['receiver_name'] = $recipient_name;
  2335. $receiver_info['user_type'] = $message_receiver['receiver_type'];
  2336. if($viewer_type == 'ADMINISTRATOR' && isset($filters['user_feed_id']) && !empty($filters['user_feed_id']))
  2337. {
  2338. if($filters['user_feed_id'] == $message_receiver['creator_id'])
  2339. {
  2340. $rights['delete'] = true;
  2341. $rights['edit'] = false;
  2342. }
  2343. }
  2344. //this makes sure that if user is student viewing his assig, other recipients wont show
  2345. if(isset($filters['direct_user_id']) && !empty($filters['direct_user_id']) && $receiver_id != $viewer_id && $viewer_type == 'STUDENT')
  2346. $result = null;
  2347. else
  2348. {
  2349. $result = array('receiver_info' => $receiver_info,
  2350. 'rights' => $rights,
  2351. 'only_student_recipients' => $only_student_recipients,
  2352. 'sent_to_community' => $sent_to_publisher
  2353. );
  2354. }
  2355. break;
  2356. case 'connections':
  2357. if ( $viewer_type == 'STUDENT' ){
  2358. $rights['reply'] = false;
  2359. }
  2360. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2361. $receiver_info['receiver_name'] = self::$layout_translator->_('connections-receivers');
  2362. if ( $message_receiver['sender_type'] == 'PUBLISHER' && $viewer_type == 'STUDENT' ){
  2363. $rights['reply'] = false;
  2364. }
  2365. if ( $message_receiver['sender_type'] == 'PUBLISHER' && $viewer_id == $message_receiver['creator_id'] ){
  2366. $rights['edit'] = true;
  2367. }
  2368. if ( $message_receiver['sender_type'] == 'PUBLISHER' && $viewer_type == 'TEACHER' ) {
  2369. if ( CoppaHandler::userIsCoppaVerified($viewer_id) ){
  2370. $rights['reply'] = false;
  2371. }
  2372. }
  2373. if( $this->feed_type == 'HOME_FEED' && $message_receiver['creator_id'] != $viewer_id){
  2374. //The user can hide this message
  2375. $rights['hide'] = true;
  2376. }
  2377. if($viewer_type == 'TEACHER' && ConnectionsHandler::getInstance()->connected($viewer_id,$message_receiver['creator_id']))
  2378. {
  2379. $rights['reply'] = true;
  2380. }
  2381. if($viewer_id == $message_receiver['creator_id'])
  2382. {
  2383. $rights['reply'] = true;
  2384. }
  2385. /*if ( $message_receiver['sender_type'] != 'PUBLISHER' ){
  2386. $receiver_info['sent_to_connections'] = true;
  2387. } */
  2388. $result = array('receiver_info' => $receiver_info,
  2389. 'rights' => $rights,
  2390. 'only_student_recipients' => false
  2391. );
  2392. break;
  2393. case 'school':
  2394. if ( $viewer_type == 'STUDENT' ){
  2395. $rights['reply'] = false;
  2396. }
  2397. if(isset($this->institutional_info['type']) && $this->institutional_info['type'] == 'STUDENT'){
  2398. $schools = $this->institutional_info['schools'];
  2399. if(isset($schools[$receiver_id])){
  2400. //student belongs to this school
  2401. if($viewer_type == 'PARENT')
  2402. $receiver_info['receiver_name'] = $this->addSchoolInfo($receiver_info, $rights, 'inst-all',true);
  2403. else
  2404. $receiver_info['receiver_name'] = $schools[$receiver_id]['school_name'];
  2405. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2406. $rights['reply'] = false;
  2407. $result = array('receiver_info' => $receiver_info,
  2408. 'rights' => $rights,
  2409. 'only_student_recipients' => false
  2410. );
  2411. }
  2412. }else {
  2413. $result = $this->addSchoolInfo($receiver_info, $rights, 'inst-all',($viewer_type == 'PARENT'));
  2414. }
  2415. break;
  2416. case 'school_vip':
  2417. if ( $viewer_type == 'STUDENT' ){
  2418. $rights['reply'] = false;
  2419. }
  2420. $result = $this->addSchoolInfo($receiver_info, $rights, 'inst-vip');
  2421. break;
  2422. case 'school_parents':
  2423. if ( $viewer_type == 'STUDENT' ){
  2424. $rights['reply'] = false;
  2425. }
  2426. $result = $this->addSchoolInfo($receiver_info, $rights, 'inst-parents');
  2427. break;
  2428. case 'district':
  2429. if ( $viewer_type == 'STUDENT' ){
  2430. $rights['reply'] = false;
  2431. }
  2432. if(isset($this->institutional_info['type']) && $this->institutional_info['type'] == 'STUDENT'){
  2433. $districts = $this->institutional_info['districts'];
  2434. //student belongs to this district
  2435. if(isset($districts[$receiver_id])){
  2436. $receiver_info['receiver_name'] = $districts[$receiver_id]['district_name'];
  2437. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2438. $rights['reply'] = false;
  2439. $result = array('receiver_info' => $receiver_info,
  2440. 'rights' => $rights,
  2441. 'only_student_recipients' => false
  2442. );
  2443. }
  2444. }else{
  2445. $result = $this->addDistrictInfo($receiver_info, $rights, 'inst-all',($viewer_type == 'PARENT'));
  2446. }
  2447. break;
  2448. case 'district_vip':
  2449. if ( $viewer_type == 'STUDENT' ){
  2450. $rights['reply'] = false;
  2451. }
  2452. $result = $this->addDistrictInfo($receiver_info, $rights, 'inst-vip');
  2453. break;
  2454. case 'district_parents':
  2455. if ( $viewer_type == 'STUDENT' ){
  2456. $rights['reply'] = false;
  2457. }
  2458. $result = $this->addDistrictInfo($receiver_info, $rights, 'inst-parents');
  2459. break;
  2460. case 'community':
  2461. if ( $viewer_type == 'STUDENT' ){
  2462. $rights['reply'] = false;
  2463. }
  2464. if($receiver_id == SUPPORT_COMMUNITY_ID){
  2465. //Support Community
  2466. if( $viewer_type == 'TEACHER' ){
  2467. if($viewer_id == EDMODO_SYSTEM_USER_ID){
  2468. //the all powerful edmodo user
  2469. $rights['delete'] = true;
  2470. }
  2471. $is_verified_teacher = CoppaHandler::userIsCoppaVerified($viewer_id);
  2472. if($message_receiver['creator_id'] != $viewer_id && !$is_verified_teacher){
  2473. $rights['reply'] = false;
  2474. }
  2475. }
  2476. }
  2477. else if($receiver_id == ADMIN_SUPPORT_COMMUNITY_ID){
  2478. //Admin Support Community
  2479. if($viewer_id == EDMODO_SYSTEM_USER_ID){
  2480. //the all powerful edmodo user
  2481. $rights['delete'] = true;
  2482. }
  2483. }
  2484. else if( $this->feed_type == 'HOME_FEED' && $message_receiver['creator_id'] != $viewer_id){
  2485. //The user can hide this message
  2486. $rights['hide'] = true;
  2487. // The user can only reply if he's verified
  2488. $current = Profiles::getInstance()->find($viewer_id)->current();
  2489. if($current!==NULL){
  2490. $profile=$current->toArray();
  2491. if ( !CoppaHandler::userIsCoppaVerified($viewer_id) ){
  2492. $rights['reply'] = false;
  2493. }
  2494. }
  2495. }
  2496. else {
  2497. // The user can only reply if he's verified
  2498. $current = Profiles::getInstance()->find($viewer_id)->current();
  2499. if($current!==NULL){
  2500. $profile=$current->toArray();
  2501. if ( !CoppaHandler::userIsCoppaVerified($viewer_id) ){
  2502. $rights['reply'] = false;
  2503. }
  2504. }
  2505. }
  2506. if( $message_receiver['creator_id'] == $viewer_id || SubjectCommunities::getInstance()->userAdminsCommunity($viewer_id, $receiver_id) ){
  2507. $rights['delete'] = true;
  2508. }
  2509. if($viewer_type == 'STUDENT')
  2510. {
  2511. $rights['reply'] = false;
  2512. }
  2513. $result = array('receiver_info' => SubjectCommunityHandler::getInstance($language)->getReceiverInfo($receiver_id),
  2514. 'rights' => $rights,
  2515. 'only_student_recipients' => false,
  2516. 'sent_to_community' => true
  2517. );
  2518. break;
  2519. }
  2520. return $result;
  2521. }
  2522. private function addDistrictInfo($receiver_info, $rights, $translation_key, $use_key = false){
  2523. $result = null;
  2524. $receiver_id = $receiver_info['id'];
  2525. if(isset($this->institutional_info['district_id']) && $this->institutional_info['district_id'] == $receiver_id){
  2526. //user belongs to this district
  2527. $receiver_info['receiver_name'] = self::$layout_translator->_($translation_key, $this->institutional_info['district_name']);
  2528. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2529. //check if the current user is a district admin and has rights to delete the message
  2530. if(isset($this->institutional_info['is_district_admin'])){
  2531. $rights['delete'] = true;
  2532. }
  2533. $result = array('receiver_info' => $receiver_info,
  2534. 'rights' => $rights,
  2535. 'only_student_recipients' => false
  2536. );
  2537. }
  2538. elseif( isset($this->parent_info['students_info_for_parent']['students_districts_by_id'][$receiver_id]) ){
  2539. if($use_key)
  2540. $receiver_info['receiver_name'] = self::$layout_translator->_($translation_key, $this->parent_info['students_info_for_parent']['students_districts_by_id'][$receiver_id]['district_name']);
  2541. else
  2542. $receiver_info['receiver_name'] = self::$layout_translator->_('inst-parents-for-parent', $this->parent_info['students_info_for_parent']['students_districts_by_id'][$receiver_id]['district_name']);
  2543. $receiver_info['receiver_name'] = $this->addChildrensNames($receiver_info['receiver_name'], $this->parent_info['students_info_for_parent']['students_districts_by_id'][$receiver_id]['student_ids']);
  2544. $receiver_info['receiver_color'] = $this->parent_info['students_info_for_parent']['students_districts_by_id'][$receiver_id]['hex'];
  2545. $rights['reply'] = false;
  2546. $result = array(
  2547. 'receiver_info' => $receiver_info,
  2548. 'rights' => $rights
  2549. );
  2550. }
  2551. return $result;
  2552. }
  2553. private function addSchoolInfo($receiver_info, $rights, $translation_key,$use_key = false){
  2554. $result = null;
  2555. $receiver_id = $receiver_info['id'];
  2556. if(isset($this->institutional_info['school_id']) && $this->institutional_info['school_id'] == $receiver_id){
  2557. //user belongs to this school (teacher/school admin)
  2558. $receiver_info['receiver_name'] = self::$layout_translator->_($translation_key, $this->institutional_info['school_name']);
  2559. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2560. if(isset($this->institutional_info['is_school_admin'])){
  2561. $rights['delete'] = true;
  2562. }
  2563. $result = array('receiver_info' => $receiver_info,
  2564. 'rights' => $rights,
  2565. 'only_student_recipients' => false
  2566. );
  2567. }else if(isset($this->institutional_info['is_district_admin'])){
  2568. if(isset($this->institutional_info['district_schools'][$receiver_id])){
  2569. $school_name = $this->institutional_info['district_schools'][$receiver_id];
  2570. }else{
  2571. $school = Schools::getInstance()->find($receiver_id)->current();
  2572. $school_name = $school['school_name'];
  2573. }
  2574. $receiver_info['receiver_name'] = self::$layout_translator->_($translation_key, $school_name);
  2575. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2576. $rights['delete'] = true;
  2577. $result = array('receiver_info' => $receiver_info,
  2578. 'rights' => $rights,
  2579. 'only_student_recipients' => false
  2580. );
  2581. }
  2582. elseif( isset($this->parent_info['students_info_for_parent']['students_schools_by_id'][$receiver_id]) ){
  2583. if($use_key)
  2584. $receiver_info['receiver_name'] = self::$layout_translator->_($translation_key, $this->parent_info['students_info_for_parent']['students_schools_by_id'][$receiver_id]['school_name']);
  2585. else
  2586. $receiver_info['receiver_name'] = self::$layout_translator->_('inst-parents-for-parent', $this->parent_info['students_info_for_parent']['students_schools_by_id'][$receiver_id]['school_name']);
  2587. $receiver_info['receiver_name'] = $this->addChildrensNames($receiver_info['receiver_name'], $this->parent_info['students_info_for_parent']['students_schools_by_id'][$receiver_id]['student_ids']);
  2588. $receiver_info['receiver_color'] = $this->parent_info['students_info_for_parent']['students_schools_by_id'][$receiver_id]['hex'];
  2589. $rights['reply'] = false;
  2590. $result = array(
  2591. 'receiver_info' => $receiver_info,
  2592. 'rights' => $rights
  2593. );
  2594. }
  2595. else{
  2596. $school = Schools::getInstance()->find($receiver_id)->current();
  2597. $school_name = $school['school_name'];
  2598. $receiver_info['receiver_name'] = self::$layout_translator->_($translation_key, $school_name);
  2599. $receiver_info['receiver_color'] = EDMODO_COLOR;
  2600. $result = array('receiver_info' => $receiver_info,
  2601. 'rights' => $rights,
  2602. 'only_student_recipients' => false
  2603. );
  2604. }
  2605. return $result;
  2606. }
  2607. private function getModelInstance($type){
  2608. $model = null;
  2609. switch($type){
  2610. case GROUP:
  2611. $model = Groups::getInstance();
  2612. break;
  2613. }
  2614. return $model;
  2615. }
  2616. public function processNewComments($messages, $comment_ids, $user_id)
  2617. {
  2618. if( count($comment_ids) )
  2619. {
  2620. $spotlight_map = $this->getSpottedReplies($user_id);
  2621. //-------------------------------
  2622. // Set a flag to see if the Spotlight should be refreshed
  2623. foreach( $comment_ids as $comment_id => $i)
  2624. {
  2625. $messages[$i]['spotlight'] = isset($spotlight_map[$comment_id]);
  2626. }
  2627. }
  2628. return $messages;
  2629. }
  2630. /**
  2631. * Creates a boolean map where the key is the message_id of the reply.
  2632. * It stores the resulting array in memory so that when called again, it doesn't have to do another DB call
  2633. * @param int $user_id id of the user which spotted replies should be fetched from
  2634. */
  2635. public function getSpottedReplies($user_id)
  2636. {
  2637. if( !isset($this->spotted_replies[$user_id]) )
  2638. {
  2639. //-------------------------------
  2640. // Get the comment ids in the Spotlight for this user
  2641. $cids = Spotlights::getInstance()->getSpottedIds($user_id, 'REPLY');
  2642. $spotted_replies = array();
  2643. foreach( $cids as $cid )
  2644. {
  2645. $spotted_replies[$cid] = true;
  2646. }
  2647. $this->spotted_replies[$user_id] = $spotted_replies;
  2648. }
  2649. return $this->spotted_replies[$user_id];
  2650. }
  2651. /**
  2652. * Prepares messages array for displaying. Each message is succeeded by its respective comments
  2653. * @param array $messages with the main messages
  2654. * @param array $message_ids contains the ids of the main messages along with their index in the $messages array
  2655. * @param string $language viewing user's language
  2656. * @param int $user_id base user id for message retrieval
  2657. * @param string $user_type viewing user's type
  2658. * @param array $filters
  2659. * @return array: list with all the messages and comments properly arranged for display
  2660. */
  2661. private function processComments( $messages, $message_ids, $language, $user_id, $user_type, $filters = array() ){
  2662. $processed_messages = $messages;
  2663. $final_msg_count = count($messages);
  2664. $profiles_model = Profiles::getInstance();
  2665. if(count($message_ids)){
  2666. $limit = MAX_REPLIES_FOR_POST;
  2667. // NOTE:: Currently this logic only sets the limit for the Apps-API,
  2668. // but we enable the comments-limit for both the website & the Mobile-API.
  2669. if ( ( ! self::$is_api_call && SECONDARY_THEME_ENABLED) || self::$limit_comments_query ){
  2670. $limit = DISPLAYED_COMMENT_COUNT;
  2671. }
  2672. $comments = NewComments::getInstance()->getCommentsForMessagesSafe(array_keys($message_ids), true, $limit);
  2673. // Sender thumbs are fetched a max of once per different user
  2674. $sender_thumbs = array();
  2675. foreach ($comments as $comment){
  2676. if ( empty( $sender_thumbs[$comment['creator_id']] ) ){
  2677. $sender_thumbs[$comment['creator_id']] = $profiles_model->getUserThumbnailSafe( $comment['creator_id'], $comment['username'] );
  2678. }
  2679. }
  2680. foreach( $comments as $comment ){
  2681. // Get the message_id
  2682. $msg_id = $comment['comment_to'];
  2683. //-------------------------------
  2684. // Get the message array index in the "messages" array
  2685. $i = $message_ids[$msg_id];
  2686. if( $user_type != 'PARENT' || $messages[$i]['type'] != 'assignment'){
  2687. // Parents shouldn't see replies to assignments
  2688. $comment['sent'] = ($user_id == $comment['creator_id']);
  2689. $comment['sender_thumb'] = $sender_thumbs[$comment['creator_id']];
  2690. unset( $comment['username'] );
  2691. $comment['delete_rights'] =
  2692. $comment['sent'] //I sent the reply
  2693. || $messages[$i]['public_rights'] //I created a group where the original message was sent to
  2694. || (isset($this->institutional_info['is_school_admin']) && $messages[$i]['delete_rights']) //I'm a school admin and can delete the original message
  2695. || (isset($this->institutional_info['is_district_admin']) && $messages[$i]['delete_rights']) //I'm a district admin and can delete the original message
  2696. || ($user_type == 'ADMINISTRATOR' && $comment['creator_id'] == $filters['user_feed_id']) //I'm a school admin and can delete the original message
  2697. || ($user_type == 'TEACHER' && $messages[$i]['only_student_recipients']) //I'm a teacher and the original message was only sent to individual users
  2698. || $user_id == EDMODO_SYSTEM_USER_ID; //I'm Mr.Edmodo!
  2699. //Introducing New Edit Rights for Comments, basic case, use the same delete
  2700. $comment['edit_rights'] = $comment['delete_rights'];
  2701. if(($user_id != $comment['creator_id']) && $comment['sender_type'] == 'PARENT'){
  2702. $comment['edit_rights'] = false;
  2703. }
  2704. if(($user_id != $comment['creator_id']) && $user_type == 'ADMINISTRATOR'){
  2705. $comment['edit_rights'] = false;
  2706. }
  2707. foreach($messages[$i]['receivers'] as $receiver){
  2708. if($user_type == 'STUDENT' && $receiver['type'] == 'group' && $receiver['moderated'] ){
  2709. $comment['edit_rights'] = false;
  2710. break;
  2711. }
  2712. if(($user_id != $comment['creator_id']) && $comment['sender_type'] == 'TEACHER'){
  2713. //what about co-teacher?
  2714. if($receiver['type'] == 'group' && $receiver['group_creator_id'] != $user_id){
  2715. $comment['edit_rights'] = false;
  2716. }
  2717. if($receiver['type'] == 'group' && $receiver['group_creator_id'] == $user_id){
  2718. $comment['edit_rights'] = true;
  2719. break;
  2720. }
  2721. if($receiver['type'] == 'user'){
  2722. $comment['edit_rights'] = false;
  2723. }
  2724. }
  2725. }
  2726. $this->processMessageInfo($comment, $language);
  2727. //Get the position of the next message in the feed
  2728. $comment_pos = $final_msg_count;
  2729. foreach($processed_messages as $key => $proc_message){
  2730. if(isset($proc_message['message_id']) && $proc_message['message_id'] == $msg_id){
  2731. //original message
  2732. $processed_messages[$key]['comment_count'] = $comment['comment_count'];
  2733. if($processed_messages[$key]['comment_count'] >= MAX_REPLIES_FOR_POST){
  2734. //This post has reached the max number of replies
  2735. $processed_messages[$key]['reply_rights'] = 0;
  2736. }
  2737. }
  2738. if(isset($messages[$i + 1]) && isset($messages[$i + 1]['message_id'], $proc_message['message_id']) && $messages[$i + 1]['message_id'] == $proc_message['message_id']){
  2739. //next message
  2740. $comment_pos = $key;
  2741. }
  2742. }
  2743. //insert the comment into the $processed_messages array
  2744. array_splice($processed_messages, $comment_pos, 0, array($comment));
  2745. $final_msg_count++;
  2746. }
  2747. }
  2748. }
  2749. return $processed_messages;
  2750. }
  2751. public static function getMaxIdsInStream($all_messages){
  2752. $max_message_id = 0;
  2753. $max_comment_id = 0;
  2754. $message_ids = array();
  2755. if(isset($all_messages)){
  2756. foreach($all_messages as $message){
  2757. if(isset($message['message_id'])){
  2758. $message_ids[] = $message['message_id'];
  2759. if($message['message_id'] > $max_message_id){
  2760. $max_message_id = $message['message_id'];
  2761. }
  2762. }else if(isset($message['comment_id']) && $message['comment_id'] > $max_comment_id){
  2763. $max_comment_id = $message['comment_id'];
  2764. }
  2765. }
  2766. }
  2767. return array('message_ids_in_stream' => $message_ids, 'max_message_id' => $max_message_id, 'max_comment_id' => $max_comment_id);
  2768. }
  2769. public function userHasRightsToAlterMessage($user_info, $message_id, $is_comment = false, $viewed_id = 0){
  2770. $user_has_alter_rights = false;
  2771. if( $user_info['user_id'] == EDMODO_SYSTEM_USER_ID )
  2772. {
  2773. $user_has_alter_rights = true;
  2774. }
  2775. else
  2776. {
  2777. if ( $is_comment ){
  2778. $message_info = NewComments::getInstance()->getCommentInfo($message_id);
  2779. }
  2780. else{
  2781. $message_info = Messages::getInstance()->getMessageInfo($message_id);
  2782. }
  2783. if( $message_info['creator_id'] == $user_info['user_id'] ){
  2784. $user_has_alter_rights = true;
  2785. }
  2786. elseif( $user_info['type'] != 'STUDENT' ){
  2787. if ( $is_comment ){
  2788. $message_recipients = Messages::getInstance()->getMessageRecipients($message_info['comment_to']);
  2789. }
  2790. else{
  2791. $message_recipients = Messages::getInstance()->getMessageRecipients($message_id);
  2792. }
  2793. $groups = Groups::getInstance();
  2794. for( $i = 0; $i < count($message_recipients) && !$user_has_alter_rights; $i++ ){
  2795. $message_recipient = $message_recipients[$i];
  2796. switch($message_recipient['posted_in']){
  2797. case 'user':
  2798. if( $message_recipient['posted_in_id'] == $user_info['user_id'] ){
  2799. //direct message to me (a teacher)
  2800. $user_has_alter_rights = true;
  2801. }
  2802. else {
  2803. // original message was sent by me (a teacher)
  2804. $original_message_info = Messages::getInstance()->find($message_info['comment_to'])->current();
  2805. if ( $original_message_info['creator_id'] == $user_info['user_id'] ){
  2806. $user_has_alter_rights = true;
  2807. }
  2808. }
  2809. if($user_info['type'] == 'ADMINISTRATOR' && UsersHandler::getInstance()->userAdminsUser( $user_info, $message_info['creator_id']))
  2810. {
  2811. $user_has_alter_rights = true;
  2812. }
  2813. break;
  2814. case 'group':
  2815. case 'group_parents':
  2816. $group_info = $groups->getGroupInfoForPossibleMember($message_recipient['posted_in_id'], $user_info['user_id']);
  2817. if( $group_info['user_owns_group'] == 1 || $group_info['co_teacher'] == 1 ){
  2818. $user_has_alter_rights = true;
  2819. }
  2820. if($user_info['type'] == 'ADMINISTRATOR' && UsersHandler::getInstance()->userAdminsUser( $user_info, $message_info['creator_id'] ) )
  2821. {
  2822. $user_has_alter_rights = true;
  2823. }
  2824. break;
  2825. case 'school':
  2826. case 'school_vip':
  2827. case 'school_parents':
  2828. if($user_info['type'] != 'STUDENT'){
  2829. //check if the teacher/admin is a member of the school
  2830. $user_school = Profiles::getInstance()->getIfUserVerifiedForSchool($user_info['user_id'], $message_recipient['posted_in_id']);
  2831. if( !empty($user_school) && ($user_school['code_verified'] == 1 || $user_school['admin_rights'] == 'SCHOOL') ){
  2832. $user_has_alter_rights = true;
  2833. }else{
  2834. //might be a district admin
  2835. $district_admins = Schools::getInstance()->getDistrictAdminForSchool($message_recipient['posted_in_id'], false);
  2836. foreach ( $district_admins as $district_admin ){
  2837. if ($district_admin['user_id'] == $user_info['user_id']){
  2838. $user_has_alter_rights = true;
  2839. break;
  2840. }
  2841. }
  2842. }
  2843. }
  2844. break;
  2845. case 'district':
  2846. case 'district_vip':
  2847. case 'district_parents':
  2848. if($user_info['type'] != 'STUDENT'){
  2849. //check if the teacher/admin is a member of the district
  2850. $user_school = Profiles::getInstance()->getIfUserVerifiedForSchoolsWithinDistrict($user_info['user_id'], $message_recipient['posted_in_id']);
  2851. if( !empty($user_school) && $user_school['code_verified'] == 1 ){
  2852. $user_has_alter_rights = true;
  2853. }else{
  2854. //might be a district admin
  2855. $district_admins = Districts::getInstance()->getDistrictAdmin($message_recipient['posted_in_id'], false);
  2856. foreach ( $district_admins as $district_admin ){
  2857. if ($district_admin['user_id'] == $user_info['user_id']){
  2858. $user_has_alter_rights = true;
  2859. break;
  2860. }
  2861. }
  2862. }
  2863. }
  2864. break;
  2865. case 'community':
  2866. // check if the user is an admin of the community
  2867. if (SubjectCommunities::getInstance()->userAdminsCommunity($user_info['user_id'], $message_recipient['posted_in_id'])){
  2868. $user_has_alter_rights = true;
  2869. }
  2870. break;
  2871. }
  2872. }
  2873. }
  2874. }
  2875. return $user_has_alter_rights;
  2876. }
  2877. /**
  2878. * Returns true if the user given by $user_info has the rights to send a message to all of the receivers in $receivers
  2879. * @param array $user_info information of a user that's trying to send a message
  2880. * @param array $receivers all the receivers the user is trying to send a message to
  2881. * @return bool: true if the user has rights to send a message to every one of the receivers
  2882. */
  2883. public function userHasRightsToSendMessage($user_info, $receivers, $message_data, $is_comment = false){
  2884. $user_has_send_rights = true;
  2885. if ( !$is_comment ) {
  2886. $params = array('language' => 'en', 'account_info' => $user_info, 'exclude_publishers_from_results' => false );
  2887. $possible_receivers = ShareboxHandler::getInstance()->getPossibleReceivers($params);
  2888. // Right to send a message directly to each individual are checked
  2889. if(isset($receivers['people']))
  2890. {
  2891. foreach( $receivers['people'] as $person ){
  2892. $user_found = false;
  2893. foreach ( $possible_receivers as $possible_receiver ){
  2894. if ( $possible_receiver['type'] == 'user' && $possible_receiver['id'] == $person ){
  2895. $user_found = true;
  2896. }
  2897. }
  2898. if (!$user_found) {
  2899. // Check if the user is actually a publisher and the sender a verified teacher
  2900. if ( !Users::getInstance()->userCanSendMessageToPublisher( $user_info['user_id'], $person ) ){
  2901. $user_has_send_rights = false;
  2902. break;
  2903. }
  2904. }
  2905. }
  2906. }
  2907. // Right to send a message to other locations is checked
  2908. if ( $user_has_send_rights ){
  2909. for( $i = 0; $i < count($receivers['locations']) && $user_has_send_rights; $i++ ){
  2910. $location = $receivers['locations'][$i];
  2911. switch( $location['type'] ){
  2912. case 'group':
  2913. case 'group_parents':
  2914. $group_found = false;
  2915. foreach ( $possible_receivers as $possible_receiver ){
  2916. if ( $possible_receiver['type'] == 'group' && $possible_receiver['id'] == $location['id'] ){
  2917. if ( $message_data['type'] == 'text' ){
  2918. $group_found = true;
  2919. }
  2920. else if ( $user_info['type'] != 'STUDENT' ){
  2921. $group_found = true;
  2922. }
  2923. }
  2924. }
  2925. if (!$group_found) {
  2926. $user_has_send_rights = false;
  2927. }
  2928. break;
  2929. case 'school':
  2930. case 'school_parents':
  2931. if($user_info['type'] == 'STUDENT'){
  2932. $user_has_send_rights = false;
  2933. }else{
  2934. $school_found = false;
  2935. foreach ( $possible_receivers as $possible_receiver ){
  2936. if ( $possible_receiver['type'] == 'school' && $possible_receiver['id'] == $location['id'] ){
  2937. $school_found = true;
  2938. }
  2939. }
  2940. if (!$school_found) {
  2941. $user_has_send_rights = false;
  2942. }
  2943. }
  2944. break;
  2945. case 'school_vip':
  2946. if($user_info['type'] == 'STUDENT'){
  2947. $user_has_send_rights = false;
  2948. }else{
  2949. $school_found = false;
  2950. foreach ( $possible_receivers as $possible_receiver ){
  2951. if ( $possible_receiver['type'] == 'school_vip' && $possible_receiver['id'] == $location['id'] ){
  2952. $school_found = true;
  2953. }
  2954. }
  2955. if (!$school_found) {
  2956. $user_has_send_rights = false;
  2957. }
  2958. }
  2959. break;
  2960. case 'district':
  2961. case 'district_parents':
  2962. if($user_info['type'] == 'STUDENT'){
  2963. $user_has_send_rights = false;
  2964. }else{
  2965. $district_found = false;
  2966. foreach ( $possible_receivers as $possible_receiver ){
  2967. if ( $possible_receiver['type'] == 'district' && $possible_receiver['id'] == $location['id'] ){
  2968. $district_found = true;
  2969. }
  2970. }
  2971. if (!$district_found) {
  2972. $user_has_send_rights = false;
  2973. }
  2974. }
  2975. break;
  2976. case 'district_vip':
  2977. if($user_info['type'] == 'STUDENT'){
  2978. $user_has_send_rights = false;
  2979. }else{
  2980. $district_found = false;
  2981. foreach ( $possible_receivers as $possible_receiver ){
  2982. if ( $possible_receiver['type'] == 'district_vip' && $possible_receiver['id'] == $location['id'] ){
  2983. $district_found = true;
  2984. }
  2985. }
  2986. if (!$district_found) {
  2987. $user_has_send_rights = false;
  2988. }
  2989. }
  2990. break;
  2991. case 'edmodo':
  2992. case 'all-groups':
  2993. case 'connections':
  2994. if ($user_info['type'] != 'TEACHER' && $user_info['type'] != 'PUBLISHER' ){
  2995. $user_has_send_rights = false;
  2996. }
  2997. break;
  2998. case 'community':
  2999. $user_status = SubjectCommunities::getInstance()->getUserStatus($user_info, $location['id']);
  3000. if ( $user_status != ADMINS && $user_status != FOLLOWS_CAN_POST && $user_status != CAN_POST ){
  3001. $user_has_send_rights = false;
  3002. }
  3003. break;
  3004. }
  3005. }
  3006. }
  3007. }
  3008. else{
  3009. // For a comment type message, we only check if the current sender can send to one of the comment's recipients
  3010. $user_has_send_rights = false;
  3011. $params = array('language' => 'en', 'account_info' => $user_info, 'exclude_publishers_from_results' => false );
  3012. $possible_receivers = ShareboxHandler::getInstance()->getPossibleReceivers($params);
  3013. // Right to send a message directly to each individual are checked
  3014. foreach( $receivers['people'] as $person ){
  3015. $receiver_info = Users::getInstance()->find($person);
  3016. if ( $receiver_info['type'] == 'PUBLISHER' ){
  3017. $user_has_send_rights = true;
  3018. break;
  3019. }
  3020. foreach ( $possible_receivers as $possible_receiver ){
  3021. if ( $person == $user_info['user_id'] ){
  3022. $user_has_send_rights = true;
  3023. break;
  3024. }
  3025. if ( $possible_receiver['type'] == 'user' && $possible_receiver['id'] == $person ){
  3026. $user_has_send_rights = true;
  3027. break;
  3028. }
  3029. }
  3030. }
  3031. // Right to send a message to other locations is checked
  3032. $keep_checking = true;
  3033. for( $i = 0; $i < count($receivers['locations']) && $keep_checking; $i++ ){
  3034. $location = $receivers['locations'][$i];
  3035. switch( $location['type'] ){
  3036. case 'group':
  3037. case 'group_parents':
  3038. if ( $user_info['type'] != 'PARENT' ){
  3039. foreach ( $possible_receivers as $possible_receiver ){
  3040. if ( $possible_receiver['type'] == 'group' && $possible_receiver['id'] == $location['id'] ){
  3041. $user_has_send_rights = true;
  3042. break;
  3043. }
  3044. }
  3045. }
  3046. elseif( $location['type'] == 'group_parents' ){
  3047. $parents_groups = ParentsStudents::getInstance()->getParentsGroups($user_info['user_id']);
  3048. foreach ( $parents_groups as $group ){
  3049. if ( $group['group_id'] == $location['id'] ){
  3050. $user_has_send_rights = true;
  3051. break;
  3052. }
  3053. }
  3054. }
  3055. break;
  3056. case 'school':
  3057. case 'school_vip':
  3058. case 'school_parents':
  3059. if($user_info['type'] != 'STUDENT'){
  3060. if ($user_info['type'] != 'PARENT'){
  3061. foreach ( $possible_receivers as $possible_receiver ){
  3062. if ( ($possible_receiver['type'] == 'school' || $possible_receiver['type'] == 'school_vip') && $possible_receiver['id'] == $location['id'] ){
  3063. $user_has_send_rights = true;
  3064. break;
  3065. }
  3066. }
  3067. }
  3068. else{
  3069. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo($user_info);
  3070. if(count($students_info['student_ids'])){
  3071. $students_info = ParentsHandler::getInstance()->getStudentsGroupsForParent($students_info);
  3072. }
  3073. if ( isset($students_info['students_schools_by_id'][$location['id']]) ){
  3074. $user_has_send_rights = true;
  3075. break;
  3076. }
  3077. }
  3078. }else{
  3079. $user_has_send_rights = false;
  3080. $keep_checking = false;
  3081. }
  3082. break;
  3083. case 'district':
  3084. case 'district_vip':
  3085. case 'district_parents':
  3086. if($user_info['type'] != 'STUDENT'){
  3087. if ( $user_info['type'] != 'PARENT' ){
  3088. foreach ( $possible_receivers as $possible_receiver ){
  3089. if ( ($possible_receiver['type'] == 'district' || $possible_receiver['type'] == 'district_vip') && $possible_receiver['id'] == $location['id'] ){
  3090. $user_has_send_rights = true;
  3091. }
  3092. }
  3093. }
  3094. else {
  3095. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo($user_info);
  3096. if(count($students_info['student_ids'])){
  3097. $students_info = ParentsHandler::getInstance()->getStudentsGroupsForParent($students_info);
  3098. }
  3099. if ( isset($students_info['students_districts_by_id'][$location['id']]) ){
  3100. $user_has_send_rights = true;
  3101. break;
  3102. }
  3103. }
  3104. }else{
  3105. $user_has_send_rights = false;
  3106. $keep_checking = false;
  3107. }
  3108. break;
  3109. case 'all-groups':
  3110. case 'connections':
  3111. case 'community':
  3112. if ($user_info['type'] == 'TEACHER' || $user_info['type'] == 'PUBLISHER' ){
  3113. $is_verified_teacher = CoppaHandler::userIsCoppaVerified($user_info['user_id']);
  3114. if ($is_verified_teacher) {
  3115. $user_has_send_rights = true;
  3116. }
  3117. else if ($location['id'] == SUPPORT_COMMUNITY_ID) {
  3118. $original_message = Messages::getInstance()->find($message_data['comment_to'])->current()->toArray();
  3119. if ($original_message['creator_id'] == $user_info['user_id']) {
  3120. $user_has_send_rights = true;
  3121. } else {
  3122. $user_has_send_rights = false;
  3123. $keep_checking = false;
  3124. }
  3125. }
  3126. else if($user_info['type'] == 'PUBLISHER' && $location['type'] === 'connections'){
  3127. $user_has_send_rights = true;
  3128. $keep_checking = false;
  3129. } else {
  3130. $user_has_send_rights = false;
  3131. $keep_checking = false;
  3132. }
  3133. }elseif($user_info['type'] == 'ADMINISTRATOR' && $location['id'] == ADMIN_SUPPORT_COMMUNITY_ID )
  3134. {
  3135. $user_has_send_rights = true;
  3136. $keep_checking = false;
  3137. }
  3138. else{
  3139. $user_has_send_rights = false;
  3140. $keep_checking = false;
  3141. }
  3142. break;
  3143. }
  3144. }
  3145. }
  3146. return $user_has_send_rights;
  3147. }
  3148. /**
  3149. * Returns a group title with the names of the students appended to it
  3150. * @param string $group_title the title of the group
  3151. * @param string $language the viewing user's language
  3152. * @param array $student_ids the ids of the students
  3153. * @return string the modified group title
  3154. */
  3155. public function addChildrensNames($group_title, $student_ids){
  3156. //Students' full info should already be cached
  3157. $students = Users::getInstance()->find($student_ids);
  3158. $group_title .= ' (';
  3159. $students_count = count($students);
  3160. for($i = 0; $i < $students_count; $i++){
  3161. $group_title .= $students[$i]['first_name'];
  3162. if($i < $students_count - 1){
  3163. $group_title .= ', ';
  3164. }
  3165. }
  3166. $group_title .= ')';
  3167. return $group_title;
  3168. }
  3169. public static function formatReceivers($receivers, $language){
  3170. $users_db = Users::getInstance();
  3171. $account_info = AccountHandler::getInstance()->getAccountInfo();
  3172. $user_id = $account_info['user_id'];
  3173. $user_groups = GroupsHandler::getInstance()->getUsersGroupsInfo($user_id);
  3174. $messaging_translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'recipients.tmx', $language);
  3175. foreach($receivers as $receiver){
  3176. $receiver_info = array('type' => $receiver['posted_in'], 'id' => $receiver['posted_in_id'], 'receiver_name' => $receiver['posted_in'], 'receiver_color' => '#444444');
  3177. switch ($receiver['posted_in']) {
  3178. case 'group':
  3179. $group = array();
  3180. if(isset($user_groups['groups'][$receiver['posted_in_id']])){
  3181. $group = $user_groups['groups'][$receiver['posted_in_id']];
  3182. }
  3183. elseif(in_array($receiver['posted_in_id'],$user_groups['archived_group_ids'])){
  3184. $group = Groups::getInstance()->getGroup($receiver['posted_in_id'],false,false,$user_id);
  3185. }
  3186. if( !empty($group) ){
  3187. $receiver_info['receiver_name'] = $group['title'];
  3188. $receiver_info['receiver_color'] = $group['hex'];
  3189. $all_receivers[] = $receiver_info;
  3190. }
  3191. break;
  3192. case 'user':
  3193. $user = $users_db->getUserInfo($receiver['posted_in_id'],true);
  3194. $receiver_info['receiver_name'] = self::formatName($user,$language);
  3195. $all_receivers[] = $receiver_info;
  3196. break;
  3197. case 'group_parents':
  3198. $group = array();
  3199. if(isset($user_groups['groups'][$receiver['posted_in_id']])){
  3200. $group = $user_groups['groups'][$receiver['posted_in_id']];
  3201. }
  3202. elseif(in_array($receiver['posted_in_id'],$user_groups['archived_group_ids'])){
  3203. $group = Groups::getInstance()->getGroup($receiver['posted_in_id'],false,false,$user_id);
  3204. }
  3205. if( !empty($group) ){
  3206. $receiver_info['receiver_name'] = $messaging_translator->_('inst-parents', $group['title']);
  3207. $receiver_info['receiver_color'] = $group['hex'];
  3208. $all_receivers[] = $receiver_info;
  3209. }
  3210. break;
  3211. case 'school':
  3212. if(isset($account_info['school_id']) && $account_info['school_id'] == $receiver['posted_in_id']){
  3213. $school_name_tmp = $account_info['school_name'];
  3214. }
  3215. else{
  3216. $school = Schools::getInstance()->getSchoolById($receiver['posted_in_id']);
  3217. $school_name_tmp = $school['school_name'];
  3218. }
  3219. $receiver_info['receiver_name'] = $messaging_translator->_('inst-all', $school_name_tmp);
  3220. $receiver_info['type'] = 'group';
  3221. $all_receivers[] = $receiver_info; //array('type'=>'group','name'=>$school_name,'hex'=> EDMODO_COLOR);
  3222. break;
  3223. case 'school_vip':
  3224. if(isset($account_info['school_id']) && $account_info['school_id'] == $receiver['posted_in_id']){
  3225. $school_name_tmp = $account_info['school_name'];
  3226. }
  3227. else{
  3228. $school = Schools::getInstance()->getSchoolById($receiver['posted_in_id']);
  3229. $school_name_tmp = $school['school_name'];
  3230. }
  3231. $receiver_info['receiver_name'] = $messaging_translator->_('inst-vip', $school_name_tmp);
  3232. $receiver_info['type'] = 'group';
  3233. $all_receivers[] = $receiver_info;
  3234. break;
  3235. case 'district':
  3236. if(isset($account_info['district_id']) && $account_info['district_id'] == $receiver['posted_in_id']){
  3237. $school_name_tmp = $account_info['district_name'];
  3238. }
  3239. else{
  3240. $school = Districts::getInstance()->getDistrictById($receiver['posted_in_id']);
  3241. $school_name_tmp = $school['name'];
  3242. }
  3243. $receiver_info['receiver_name'] = $messaging_translator->_('inst-all', $school_name_tmp);
  3244. $receiver_info['type'] = 'group';
  3245. $all_receivers[] = $receiver_info;
  3246. break;
  3247. case 'district_vip':
  3248. if(isset($account_info['district_id']) && $account_info['district_id'] == $receiver['posted_in_id']){
  3249. $school_name_tmp = $account_info['district_name'];
  3250. }
  3251. else{
  3252. $school = Districts::getInstance()->getDistrictById($receiver['posted_in_id']);
  3253. $school_name_tmp = $school['name'];
  3254. }
  3255. $receiver_info['receiver_name'] = $messaging_translator->_('inst-vip', $school_name_tmp);
  3256. $receiver_info['type'] = 'group';
  3257. $all_receivers[] = $receiver_info;
  3258. break;
  3259. }
  3260. }
  3261. return $all_receivers;
  3262. }
  3263. /**
  3264. * determines if a message is considered "long"
  3265. * @param string $message the message to check
  3266. * @return boolean the message is long or not
  3267. */
  3268. public function isLongMessage( $message )
  3269. {
  3270. $result = false;
  3271. if(strlen($message) > MAX_CHAR_LENGTH_FOR_MESSAGES || substr_count($message, HTML_BREAK_TAG) > MAX_LINE_BREAKS_FOR_MESSAGES)
  3272. {
  3273. $result = true;
  3274. }
  3275. return $result;
  3276. }
  3277. /**
  3278. * Formats a long message returning the cutted version, looks for the ritght place
  3279. * to cut, tries to avoid cutting anchors in the middle
  3280. * @param string $message the message to format
  3281. * @param boolean $add_dots if we need to add "..." in the end
  3282. * @return string the cutted message
  3283. */
  3284. public function formatLongMessage( $message, $add_dots = true)
  3285. {
  3286. $cutted_message = '';
  3287. if(substr_count($message, HTML_BREAK_TAG) > MAX_LINE_BREAKS_FOR_MESSAGES && strlen($message) < MAX_CHAR_LENGTH_FOR_MESSAGES)
  3288. {
  3289. $position = strposOffset(HTML_BREAK_TAG,$message,MAX_LINE_BREAKS_FOR_MESSAGES);
  3290. }
  3291. else
  3292. {
  3293. $position = MAX_CHAR_LENGTH_FOR_MESSAGES;
  3294. $correct_space = false;
  3295. $start_searching = (MAX_CHAR_LENGTH_FOR_MESSAGES - 8);
  3296. while(!$correct_space)
  3297. {
  3298. $space_pos = 0;
  3299. if($start_searching < strlen($message) )
  3300. $space_pos = strpos($message, " ", $start_searching);
  3301. if(empty($space_pos))
  3302. {
  3303. if(strlen($message > MAX_CHAR_LENGTH_FOR_MESSAGES + 2))
  3304. $position = MAX_CHAR_LENGTH_FOR_MESSAGES + 2;
  3305. else
  3306. $position = MAX_CHAR_LENGTH_FOR_MESSAGES - 3;
  3307. $correct_space = true;
  3308. if(substr($message,$position - 3,6) == HTML_BREAK_TAG)
  3309. {
  3310. $position = $position - 3;
  3311. }
  3312. }
  3313. else if(substr($message,$space_pos - 3,6) != HTML_BREAK_TAG)
  3314. {
  3315. $position = $space_pos;
  3316. $correct_space = true;
  3317. }
  3318. else
  3319. $start_searching = $start_searching + 9;
  3320. }
  3321. if(substr_count($message, HTML_BREAK_TAG) > MAX_LINE_BREAKS_FOR_MESSAGES && strlen($message) > MAX_CHAR_LENGTH_FOR_MESSAGES)
  3322. {
  3323. $position_temp = strposOffset(HTML_BREAK_TAG,$message,MAX_LINE_BREAKS_FOR_MESSAGES);
  3324. if($position > $position_temp)
  3325. $position = $position_temp;
  3326. }
  3327. }
  3328. //preventing of cutting a link in the middle
  3329. $is_link = strrpos($message,"<a");
  3330. $is_link2 = strrpos($message,"/a>");
  3331. if(!empty($is_link) && !empty($is_link2) && $is_link < $is_link2 /*&& $is_link < $position*/)
  3332. {
  3333. //$position = $is_link;
  3334. $all_positions = strallpos($message,"<a");
  3335. foreach($all_positions as $link_pos)
  3336. {
  3337. $end_pos = strpos($message,"/a>",$link_pos);
  3338. if($link_pos < $position && $position < $end_pos)
  3339. {
  3340. $position = $link_pos;
  3341. break;
  3342. }
  3343. }
  3344. }
  3345. $cutted_message = substr($message, 0, $position);
  3346. if($add_dots)
  3347. $cutted_message .= "...";
  3348. return $cutted_message ;
  3349. }
  3350. /**
  3351. * Determines if a user has rights to SEE a message
  3352. * @param array $viewer_info the information of the viewer
  3353. * @param array $message_data the information from the message
  3354. * @param array $creator_info the informatation of the message creator
  3355. * @return boolean has rights or not
  3356. */
  3357. public function userHasRightsToReadMessage($viewer_info,$message_data,$creator_info)
  3358. {
  3359. $has_rights = false;
  3360. //$receiver_id = $message_data['posted_in_id'];
  3361. $user_id = $viewer_info['user_id'];
  3362. $user_type = $viewer_info['type'];
  3363. if($message_data['public'] == 1 || (!empty($viewer_info) && ($viewer_info['type'] == 'SUPER_USER' || $viewer_info['user_id'] == EDMODO_SYSTEM_USER_ID )))
  3364. {
  3365. $has_rights = true;
  3366. }
  3367. else if(isset($viewer_info['user_id']) && $viewer_info['user_id'] == $message_data['creator_id'])
  3368. {
  3369. $has_rights = true;
  3370. }
  3371. else
  3372. {
  3373. //hack for when a message brings no receivers but it does bring posted_in
  3374. if(count($message_data['receivers']) == 0 && !empty($message_data['posted_in']) && !empty($message_data['posted_in_id']))
  3375. {
  3376. $message_data['receivers'][] = array ('type' => $message_data['posted_in'], 'id' => $message_data['posted_in_id']);
  3377. }
  3378. foreach($message_data['receivers'] as $receiver)
  3379. {
  3380. $message_receiver_type = $receiver['type'];
  3381. $message_receiver_id = (isset($receiver['id']) ? $receiver['id'] : 0) ;
  3382. if($message_receiver_type == 'community')
  3383. {
  3384. //edit rights!!
  3385. $has_rights = true;
  3386. break;
  3387. }
  3388. else if ($message_receiver_type == 'user')
  3389. {
  3390. $receiver_info = Users::getInstance()->getUserInfo($message_receiver_id,true);
  3391. if($receiver_info['type'] == 'PUBLISHER')
  3392. {
  3393. $has_rights = true;
  3394. break;
  3395. }
  3396. }
  3397. else if ($message_receiver_type == 'connections')
  3398. {
  3399. if($creator_info['type'] == 'PUBLISHER')
  3400. {
  3401. $has_rights = true;
  3402. break;
  3403. }
  3404. }
  3405. if(!$has_rights && !empty($viewer_info))
  3406. {
  3407. //$receiver_id = $message_data['posted_in_id'];
  3408. switch($message_receiver_type){
  3409. case 'user':
  3410. if($message_receiver_id == $user_id)
  3411. {
  3412. $has_rights = true;
  3413. }
  3414. break;
  3415. case 'group':
  3416. $groups = Groups::getInstance()->getUserGroupsIds($user_id,false); //GroupsEditorHelper::getInstance()->getGroupsInfo($user_id);
  3417. if(in_array($message_receiver_id,$groups)) //array_keys($groups)
  3418. {
  3419. $has_rights = true;
  3420. } else if ($viewer_info['type'] == 'PARENT') {
  3421. $students_info = ParentsStudents::getInstance()->getParentStudents($viewer_info['user_id']);
  3422. foreach ($students_info as $si) {
  3423. $su = array('user_id' => $si['student_id'], 'type' => "STUDENT");
  3424. if ($this->userHasRightsToReadMessage($su,$message_data,$creator_info)) {
  3425. $has_rights = true;
  3426. break;
  3427. }
  3428. }
  3429. }
  3430. break;
  3431. case 'group_parents':
  3432. if($user_type == 'PARENT')
  3433. {
  3434. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo($viewer_info);
  3435. if(count($students_info['student_ids']))
  3436. {
  3437. $groups = ParentsHandler::getInstance()->getStudentsGroupsForParent($students_info);
  3438. if( in_array($message_receiver_id,$groups['students_group_ids']))
  3439. {
  3440. $has_rights = true;
  3441. }
  3442. }
  3443. }
  3444. break;
  3445. case 'school':
  3446. if(isset($viewer_info['school_id']) && $viewer_info['school_id'] == $message_receiver_id)
  3447. {
  3448. $has_rights = true;
  3449. }
  3450. if(isset($viewer_info['schools']) && in_array($message_receiver_id,array_keys($viewer_info['schools'])))
  3451. {
  3452. $has_rights = true;
  3453. }
  3454. break;
  3455. case 'school_vip':
  3456. if(($user_type == 'TEACHER' || $user_type == 'ADMINISTRATOR') && isset($viewer_info['school_id']) && $viewer_info['school_id'] == $message_receiver_id)
  3457. {
  3458. $has_rights = true;
  3459. }
  3460. break;
  3461. case 'school_parents':
  3462. if($user_type == 'PARENT')
  3463. {
  3464. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo($viewer_info);
  3465. if(count($students_info['student_ids']))
  3466. {
  3467. $groups = ParentsHandler::getInstance()->getStudentsGroupsForParent($students_info);
  3468. if( in_array($message_receiver_id,$groups['students_school_ids']))
  3469. {
  3470. $has_rights = true;
  3471. }
  3472. }
  3473. }
  3474. break;
  3475. case 'district':
  3476. if(isset($viewer_info['district_id']) && $viewer_info['district_id'] == $message_receiver_id)
  3477. {
  3478. $has_rights = true;
  3479. }
  3480. if(isset($viewer_info['districts']) && in_array($message_receiver_id,array_keys($viewer_info['districts'])))
  3481. {
  3482. $has_rights = true;
  3483. }
  3484. break;
  3485. case 'district_vip':
  3486. if(($user_type == 'TEACHER' || $user_type == 'ADMINISTRATOR') && isset($viewer_info['district_id']) && $viewer_info['district_id'] == $message_receiver_id)
  3487. {
  3488. $has_rights = true;
  3489. }
  3490. break;
  3491. case 'district_parents':
  3492. if($user_type == 'PARENT')
  3493. {
  3494. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo($viewer_info);
  3495. if(count($students_info['student_ids']))
  3496. {
  3497. $groups = ParentsHandler::getInstance()->getStudentsGroupsForParent($students_info);
  3498. if( in_array($message_receiver_id,$groups['students_district_ids']))
  3499. {
  3500. $has_rights = true;
  3501. }
  3502. }
  3503. }
  3504. break;
  3505. case 'connections':
  3506. $connections = ConnectionsHandler::getInstance()->getConnections($user_id);
  3507. foreach($connections as $connection)
  3508. {
  3509. if($connection['user_id'] == $message_data['creator_id'])
  3510. {
  3511. $has_rights = true;
  3512. break;
  3513. }
  3514. }
  3515. break;
  3516. case 'community':
  3517. $has_rights = true;
  3518. break;
  3519. }
  3520. if($has_rights == true)
  3521. {
  3522. //break foreach
  3523. break;
  3524. }
  3525. }//closes switch
  3526. }//close foreach
  3527. }//close else
  3528. return $has_rights;
  3529. }
  3530. private function preProcessPossibleGdocs(&$message_data,$attached_resources)
  3531. {
  3532. if(isset($message_data['original_message_id']) && !empty($message_data['original_message_id']))
  3533. {
  3534. $google_permisions = array();
  3535. if (!empty($attached_resources))
  3536. {
  3537. foreach($attached_resources as $resource)
  3538. {
  3539. $item = LibraryItems::getInstance()->getLibraryItem($resource);
  3540. if($item['library_item_type'] == 'LINK')
  3541. {
  3542. $google_info = GdocsMessagesPermissions::getInstance()->getPermissions($item['library_item_resource_id'],$message_data['original_message_id']);
  3543. if(!empty($google_info))
  3544. {
  3545. $extra_info = GdocsLinks::getInstance()->getGoogleDoc($google_info['link_id']);
  3546. $google_permisions[] = array_merge($google_info, $extra_info);
  3547. }
  3548. }
  3549. }
  3550. }
  3551. if(count($google_permisions) > 0)
  3552. {
  3553. $role = 'reader';
  3554. $scope = 'user';
  3555. foreach($google_permisions as $godc)
  3556. {
  3557. if($godc['role'] != 'reader')
  3558. $role = $godc['role'];
  3559. if($godc['scope'] != 'user')
  3560. $scope = $godc['scope'];
  3561. $google_docs[] = $godc;
  3562. }
  3563. $message_data['google_docs']['role'] = $role;
  3564. $message_data['google_docs']['scope'] = $scope;
  3565. $message_data['google_docs']['docs_info'] = $google_docs;
  3566. }
  3567. }
  3568. }
  3569. /**
  3570. * Check if a user can read a particular message.
  3571. *
  3572. * This is a wrapper for the userHasRightsToReadMessage() function, by accepting the $account_info for the user to check and a message_id.
  3573. *
  3574. * @param array $account_info, the account info for the user to check
  3575. * @param string $language
  3576. * @param int $message_id
  3577. * @return array|bool
  3578. */
  3579. public function userCanReadMessage($account_info, $language, $message_id) {
  3580. // get the original message
  3581. $msg_info = MessagingHelper::getInstance()->
  3582. checkMessages($language, $account_info, array('message_id' => $message_id, 'include_special_groups' => true));
  3583. if (isset($msg_info[0])) {
  3584. $msg_data = $msg_info[0];
  3585. $sender_info = array(
  3586. 'user_id' => $msg_data['creator_id'],
  3587. 'type' => $msg_data['sender_type'],
  3588. 'title' => $msg_data['sender_title'],
  3589. 'first_name' => $msg_data['sender_first_name'],
  3590. 'last_name' => $msg_data['sender_last_name']
  3591. );
  3592. // make sure that this user can read this assignment message
  3593. if (MessagingHelper::getInstance()->userHasRightsToReadMessage($account_info, $msg_data, $sender_info)) {
  3594. return $msg_data;
  3595. }
  3596. }
  3597. return false;
  3598. }
  3599. /**
  3600. * Checks if the post is being shared and is a snapshot post from the input params
  3601. * Because there is no difference in the params sent for sharing snapshot posts, nor does our system require any difference
  3602. * we need to run a series of checks to determine if it is indeed a snapshot post
  3603. *
  3604. * @param array $params - an array of values being sent for the message
  3605. * @returns bool
  3606. */
  3607. public function isSharingSnapshotPost($params){
  3608. $result = false;
  3609. //if we're sharing a post we need to make sure it's not a snapshot post
  3610. if(isset($params['share']) && isset($params['new_links'])){
  3611. if(is_string($params['new_links'])){
  3612. try{
  3613. $links = Zend_Json::decode($params['new_links']);
  3614. }catch(Exception $e){}
  3615. }else{
  3616. $params['links'];
  3617. }
  3618. //if it's not an array don't do anything
  3619. if(is_array($links)){
  3620. $links = $links[0];
  3621. if(isset($links['url']) && is_string($links['url'])){
  3622. $parts = explode('/', $links['url']);
  3623. $message_id = 0;
  3624. //any valid shared url would need to take the format /posts/:message_id
  3625. for($i=0; $i<count($parts); $i++){
  3626. if($parts[$i] === 'post'){
  3627. $message_id = isset($parts[$i + 1]) ? $parts[$i + 1] : 0;
  3628. break;
  3629. }
  3630. }
  3631. if(is_numeric($message_id) && $message_id){
  3632. $message = Messages::getInstance()->getMessageInfo($message_id);
  3633. if($message['type'] === 'app_message') $result = true;
  3634. }
  3635. }
  3636. }
  3637. }
  3638. return $result;
  3639. }
  3640. /**
  3641. * Helper to prepare various receivers (a work in progress) for message sending.
  3642. * Constructs a receivers array that is compatible with MessagingHelper
  3643. *
  3644. * @param array/int $receiver_user_ids
  3645. * @param array/int $receiver_group_ids
  3646. * @param array/int $receiver_parent_group_ids
  3647. * @return array
  3648. */
  3649. public function prepareReceivers($receiver_user_ids = array(), $receiver_group_ids = array(), $receiver_parent_group_ids = array()) {
  3650. // prepare receivers
  3651. $receivers = array('locations' => array(), 'people' => array());
  3652. if ($receiver_user_ids) {
  3653. $receivers['people'] = $receiver_user_ids;
  3654. }
  3655. if ($receiver_group_ids) {
  3656. foreach ($receiver_group_ids as $group_id) {
  3657. $receivers['locations'][] = array(
  3658. 'type' => 'group',
  3659. 'id' => $group_id,
  3660. );
  3661. }
  3662. }
  3663. if ($receiver_parent_group_ids) {
  3664. foreach ($receiver_parent_group_ids as $parent_group_id) {
  3665. $receivers['locations'][] = array(
  3666. 'type' => 'group_parents',
  3667. 'id' => $parent_group_id,
  3668. );
  3669. }
  3670. }
  3671. return $receivers;
  3672. }
  3673. }
  3674. class NotificationTestJob
  3675. {
  3676. public $data;
  3677. public function workload()
  3678. {
  3679. return $this->data;
  3680. }
  3681. public function handle()
  3682. {
  3683. return __CLASS__;
  3684. <tu tuid="get-started-alt">
  3685. <tuv xml:lang="en"><seg><![CDATA[Welcome! %1$s %1$s Now you can connect to all your classes, students, and colleaguesall in one place. %1$s %1$s Setting up your account is simple. Just complete our %2$sGet Started Checklist%3$s and voila! Youre set for anytime, anywhere learning. %1$s %1$s Now if only grading all that homework was this easy!%1$s !%1$s Sincerely, %1$s The Edmodo Team]]></seg></tuv>
  3686. <tuv xml:lang="fr"><seg><![CDATA[Bienvenue ! %1$s %1$s Vous pouvez maintenant vous connecter à toutes vos classes, tous vos étudiants et collèguesen un seul endroit.%1$s %1$s La configuration de votre compte est simple. Terminez simplement notre %2$s liste de contrôle de démarrage %3$s et voilà ! Vous êtes paré pour un apprentissage à tout moment, partout.%1$s %1$s Si seulement la notation de tous ces devoirs était aussi facile que ça !%1$s Cordialement, %1$s l'Équipe Edmodo,]]></seg></tuv>
  3687. <tuv xml:lang="es"><seg><![CDATA[¡Bienvenido! %1$s %1$s Ahora puedes conectarte a todas tus clases, alumnos y colegas... todos en un solo lugar.%1$s %1$s Configurar tu cuenta es simple. Solo completa nuestra %2$sLista para comenzar%3$s y ¡listo! Estás listo para comenzar a aprender en todo momento y lugar.%1$s¡Si solo corregir fuera así de fácil!%1$s %1$s Saludos, %1$sEl equipo Edmodo]]></seg></tuv>
  3688. </tu>
  3689. }
  3690. public function __construct($data)
  3691. {
  3692. $this->data = $data;
  3693. }
  3694. }