PageRenderTime 77ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/work.php

https://github.com/blakeparkinson/dumbgame
PHP | 1596 lines | 1209 code | 190 blank | 197 comment | 276 complexity | 82d49cd2986b0713334a07dce1e389b3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. //Following constants are the DEBUG levels
  3. define( 'DEBUG_OFF', 0 );
  4. define( 'DEBUG_CATCHS', 1 ); //Only messages from try/catch blocks will log
  5. define( 'DEBUG_FULL', 2 ); //all info messages will be logged
  6. if (isset( $argv [0] )) {
  7. define( 'CONSOLE', 1 ); //constant indicates its running from console to index.php
  8. //--------------------------------------
  9. //Whith this we include the zend context
  10. require_once ('index.php');
  11. NotificationsWorker::getInstance();
  12. }
  13. class NotificationsWorker {
  14. const MAX_EXECUTION_TIME = 3660;
  15. const WORKER_FUNCTION_SEND_NOTIFICATIONS = 'sendNotifications';
  16. const MAX_JOBS = 3660;
  17. private $shutdown; // this variable is set by the signal handler when it recieves SIGTERM
  18. //maps the type of the incoming message with the DB types
  19. private static $typeMapping = array (
  20. 'text' => 'notes',
  21. 'video' => 'messages',
  22. 'image' => 'messages',
  23. 'assignment' => 'assignments',
  24. 'system' => 'messages',
  25. 'comment' => 'replies',
  26. 'alert' => 'alerts',
  27. 'grade' => 'messages',
  28. 'poll' => 'messages',
  29. 'quiz' => 'quizzes',
  30. );
  31. private $worker;
  32. private static $starttime;
  33. private static $jobcount;
  34. private static $replyTo = NOTIFY_EMAIL;
  35. private static $log;
  36. private static $msgID = 0;
  37. private static $msgType = '';
  38. private static $expectedWorkersNumber;
  39. //self::logActions is incharge of logging according to DEBUG level
  40. /**
  41. * Setup the Notifications worker object
  42. *
  43. */
  44. private function __construct() {
  45. // install signal handler
  46. declare(ticks = 1)
  47. ;
  48. pcntl_signal( SIGTERM, array ($this, "sig_handler" ) );
  49. $this->shutdown = FALSE;
  50. self::$starttime = time();
  51. self::$jobcount=0;
  52. try {
  53. $this->worker = new GearmanWorker();
  54. $gearman_obj = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', 'gearman');
  55. $gearman_job_server_conf = $gearman_obj->get('job_server')->toArray();
  56. $added= $this->worker->addServer($gearman_job_server_conf['host'], $gearman_job_server_conf['port']);
  57. $gearman_workers_conf = $gearman_obj->get('workers')->toArray();
  58. self::$expectedWorkersNumber = $gearman_workers_conf['expected_worker_count'];
  59. $this->worker->addFunction( 'sendNotifications', 'NotificationsWorker::send_notifications' );
  60. //$this->worker->setOptions(GEARMAN_WORKER_NON_BLOCKING,TRUE); // causes the function GearmanWorker::work() to not block the caller. However, it also causes the worker to not process any jobs! is this a bug?
  61. } catch ( exception $e ) {
  62. self::logActions( "\n" . '__construct:ERROR on setup ' . $e->getMessage(), DEBUG_CATCHS );
  63. self::writeLog( 'c_' );
  64. }
  65. try {
  66. do {
  67. // check to see if we have recieved a SIGTERM signal
  68. if ($this->shutdown) {
  69. self::logActions( "Recieved kill command. Exiting gracefully", DEBUG_FULL );
  70. self::writeLog();
  71. exit( 0 );
  72. }
  73. // check to see if we have been running too long
  74. $runningtime = time() -self::$starttime;
  75. if ($runningtime > self::MAX_EXECUTION_TIME ) {
  76. self::logActions( "exiting after $runningtime seconds", DEBUG_FULL );
  77. self::writeLog();
  78. // ensure that enough workers are running then exit gracefully
  79. self::watchAndRaiseWorkers();
  80. exit( 0 );
  81. }
  82. // check to see if we have executed too many jobs
  83. if (self::$jobcount > self::MAX_JOBS ) {
  84. self::logActions( "exiting after running ".self::$jobcount.' jobs ', DEBUG_FULL );
  85. self::writeLog();
  86. // ensure that enough workers are running then exit gracefully
  87. self::watchAndRaiseWorkers();
  88. exit( 0 );
  89. }
  90. $this->worker->work();
  91. if (! ($this->worker->returnCode() == GEARMAN_IO_WAIT || $this->worker->returnCode() == GEARMAN_NO_JOBS || $this->worker->returnCode() == 0)) {
  92. self::logActions( "an error ocurred " . $this->worker->returnCode(), DEBUG_FULL );
  93. self::writeLog();
  94. }
  95. } while ( TRUE );
  96. } catch ( exception $e ) {
  97. //self::sendWarningEmail();
  98. self::logActions( "\n" . '__contruct:**** I Finished Working **** ' . $e->getMessage(), DEBUG_CATCHS );
  99. self::writeLog( 'cw_' );
  100. }
  101. }
  102. function __destruct() {
  103. try {
  104. //self::sendWarningEmail();
  105. self::logActions( "\n ---- I Died!!! ----\n", DEBUG_CATCHS );
  106. self::writeLog( 'd_' );
  107. } catch ( exception $e ) {
  108. //do nothing
  109. }
  110. }
  111. /**
  112. *
  113. * @return object GearmanHelper instance
  114. */
  115. static function getInstance() {
  116. static $instance;
  117. $instance = new self();
  118. return $instance;
  119. }
  120. /**
  121. * Main function to process and send correct notifications for an action
  122. * @param array $job serialized object from Gearman call
  123. * @return
  124. */
  125. public static function send_notifications($job) {
  126. try {
  127. if (empty( self::$starttime )) {
  128. self::$starttime = time();
  129. }
  130. if(empty(self::$jobcount)){
  131. self::$jobcount=0;
  132. }
  133. self::$jobcount++;
  134. self::logActions( '-------------------------------' . "\n" . 'NotificationsWorker::send_notifications' . "\n", DEBUG_CATCHS );
  135. $myProccessId = getmypid(); //Get self proccess ID
  136. self::logActions( "\n" . 'send_notifications:: Proccess ID : ' . $myProccessId . "\n\n", DEBUG_CATCHS );
  137. try {
  138. $workerObject = $job->workload(); //will bring the desired message
  139. $workerArray = unserialize( $workerObject );
  140. $errors=error_get_last();
  141. if(isset($errors['type']) && $errors['type']==2 && isset($errors['message']) && strstr($errors['message'],'unserialize') ){
  142. // fix the SimpleXML bug
  143. $tokens=explode(';',$workerObject);
  144. foreach($tokens as $i=>$token){
  145. if($token=='O:16:"SimpleXMLElement":1:{i:0'){
  146. $tokens[$i+2]=substr($tokens[$i+2],1);
  147. unset($tokens[$i]);
  148. }
  149. }
  150. $workerObject=implode(';',$tokens);
  151. $workerArray = unserialize( $workerObject );
  152. }
  153. if(empty($workerArray)){
  154. trigger_error('Unable to process job '.$job->handle());
  155. trigger_error($workerObject);
  156. return;
  157. }
  158. $selectedReceivers = $workerArray ['selected_receivers'];
  159. $accountInfo = $workerArray ['account_info'];
  160. $messageData = $workerArray ['message_data'];
  161. self::$msgID = isset($messageData['message_id']) ? $messageData['message_id']: null;
  162. self::$msgType = $messageData ['type'];
  163. } catch ( exception $e ) {
  164. self::logActions( "\n" . 'send_notifications: ERROR: Constructing Notification: ' . $e->getMessage() . "\n", DEBUG_CATCHS );
  165. }
  166. //--------------------------------
  167. // Log some Data
  168. $initialLogMsg = '$workerArray: ' . print_r( $workerArray, true ) . "\n";
  169. self::logActions( $initialLogMsg, DEBUG_FULL );
  170. //verify that a connection to the database is active
  171. self::ensureActiveDBConnection();
  172. try {
  173. //Call Main proccess
  174. self::process_notifications( $workerArray, $selectedReceivers, $accountInfo, $messageData );
  175. } catch ( exception $e ) {
  176. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  177. self::logActions( "\n" . 'send_notifications: ERROR processing notifications ' . $e->getMessage(), DEBUG_CATCHS );
  178. self::writeLog();
  179. }
  180. } catch ( exception $e ) {
  181. //--------------------------------
  182. // Log the Exception
  183. self::logActions( "\n" . 'send_notifications: ERROR: An Exception was thrown: ' . $e->getMessage(), DEBUG_CATCHS );
  184. self::writeLog();
  185. }
  186. }
  187. private static function ensureActiveDBConnection(){
  188. $write_db_registry_name = 'zendmodo_db';
  189. $readonly_db_registry_name = 'zendmodo_readonly_db';
  190. $databases = Zend_Registry::get('databases');
  191. $db=NULL;
  192. if (Zend_Registry::isRegistered($write_db_registry_name)) {
  193. $db = Zend_Registry::get($write_db_registry_name);
  194. }
  195. if (empty($db)) {
  196. $db_obj = $databases->db->get('zendmodo');
  197. if(empty($db_obj)){
  198. throw new Exception("no configuration defined for db");
  199. }
  200. $db = Zend_Db::factory($db_obj->adapter, $db_obj->config->toArray());
  201. if (empty($db)) {
  202. throw new Exception("failed to connect to db using configuration");
  203. } else {
  204. Zend_Registry::set($write_db_registry_name, $db);
  205. }
  206. }
  207. try{
  208. $now=$db->fetchOne('select now()');
  209. }catch(Zend_Db_Statement_Exception $e){
  210. if($e->getMessage()=="SQLSTATE[HY000]: General error: 2006 MySQL server has gone away"){
  211. trigger_error('MySQL server has gone away. Reconnecting...',E_USER_WARNING);
  212. //try to reconnect
  213. $db->closeConnection();
  214. $db->getConnection();
  215. $now=$db->fetchOne('select now()');
  216. trigger_error('Reconnected to database',E_USER_NOTICE); //write this message to the log so that we know when successful reconnects happen.
  217. }else{
  218. throw $e; // some other exception happened that we arent going to handle here.
  219. }
  220. }
  221. // check and reconnect to readonly database
  222. $readonly_db=NULL;
  223. if (Zend_Registry::isRegistered($readonly_db_registry_name)) {
  224. $readonly_db = Zend_Registry::get($readonly_db_registry_name);
  225. }
  226. if (empty($readonly_db)) {
  227. $readonly_db_obj = $databases->db->get('zendmodo_readonly');
  228. if(empty($readonly_db_obj)){
  229. throw new Exception("no configuration defined for readonly db");
  230. }
  231. $readonly_db = Zend_Db::factory($readonly_db_obj->adapter, $readonly_db_obj->config->toArray());
  232. if(empty($readonly_db)){
  233. throw new Exception("failed to connect to readonly db using configuration");
  234. }else{
  235. Zend_Registry::set($readonly_db_registry_name, $readonly_db);
  236. }
  237. }
  238. try{
  239. $now=$readonly_db->fetchOne('select now()');
  240. }catch(Zend_Db_Statement_Exception $e){
  241. if($e->getMessage()=="SQLSTATE[HY000]: General error: 2006 MySQL server has gone away"){
  242. trigger_error('Readonly MySQL server has gone away. Reconnecting...',E_USER_WARNING);
  243. //try to reconnect
  244. $readonly_db->closeConnection();
  245. $readonly_db->getConnection();
  246. $now=$readonly_db->fetchOne('select now()');
  247. trigger_error('Reconnected to readonly database',E_USER_NOTICE); //write this message to the log so that we know when successful reconnects happen.
  248. }else{
  249. throw $e; // some other exception happened that we arent going to handle here.
  250. }
  251. }
  252. }
  253. /**
  254. * Aux function to process and send correct notifications for an action
  255. * @param array $workerArray unserialized object from Gearman call
  256. * @param array $selectedReceivers the receivers of the message
  257. * @param array $accountInfo info from the sender
  258. * @param array $messageData the message data to be send
  259. * @return
  260. */
  261. private function process_notifications($workerArray, $selectedReceivers, $accountInfo, $messageData) {
  262. $allRecipients = array ();
  263. $membersOfGroup = array ();
  264. $parentsOfGroup = array ();
  265. $adminRecipients = array();
  266. $parentsGroups = array();
  267. try {
  268. //This case if for new restricted messages to only receivers that have commented
  269. if (isset( $selectedReceivers ['notification_receivers'] )) {
  270. self::logActions( '$selectedReceivers[\'notification_receivers\'] Getting through the first if', DEBUG_FULL );
  271. try {
  272. foreach ( $selectedReceivers ['notification_receivers'] as $receiver => $receiverId ) {
  273. array_push( $allRecipients, $receiverId );
  274. }
  275. //check if this user that answered is an admin
  276. if (is_array( $selectedReceivers ['locations'] )) {
  277. foreach ( $selectedReceivers ['locations'] as $location ) {
  278. $inst_admins = array();
  279. if ($location ['type'] == 'school' || $location ['type'] == 'school_vip') {
  280. $inst_admins = Schools::getInstance()->getAllSchoolAdmins( $location ['id'] );
  281. $messageData['posted_in_school'] = 1;
  282. }
  283. if ($location ['type'] == 'district' || $location ['type'] == 'district_vip') {
  284. $inst_admins = Districts::getInstance()->getDistrictMembers( $location ['id'] ,false,'admins','',true);
  285. }
  286. foreach($inst_admins as $admin)
  287. {
  288. if(isset($admin['admin_notifications']) && !empty($admin['admin_notifications']) && in_array($admin ['user_id'],$selectedReceivers ['notification_receivers']))
  289. {
  290. array_push( $adminRecipients, $admin ['user_id'] );
  291. }
  292. }
  293. unset( $inst_admins );
  294. }
  295. }
  296. } catch ( exception $e ) {
  297. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  298. self::logActions( "\n" . 'process_notifications:ERROR creating receiver list ' . $e->getMessage(), DEBUG_CATCHS );
  299. }
  300. } //This is for direct messages to get notification when they answered my message,etc
  301. else if (is_array( $selectedReceivers ['people'] ) && count( $selectedReceivers ['people'] ) == 1 &&
  302. (! is_array( $selectedReceivers ['locations'] ) || count( $selectedReceivers ['locations'] ) == 0) && $messageData ['type'] == 'comment') {
  303. self::logActions( 'process_notifications: Going through direct reply', DEBUG_FULL );
  304. try {
  305. //do direct reply answer
  306. $originalSenderInfo = Messages::getInstance()->getSenderInfoByMessageId( $messageData ['comment_to'] );
  307. if ( $originalSenderInfo['send_notifications'] != '0' ){
  308. if ($originalSenderInfo ['user_id'] == $accountInfo ['user_id'])
  309. $newReceiver = $selectedReceivers ['people'] [0];
  310. else
  311. $newReceiver = $originalSenderInfo ['user_id'];
  312. array_push( $allRecipients, $newReceiver );
  313. }
  314. } catch ( exception $e ) {
  315. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  316. self::logActions( "\n" . 'process_notifications:ERROR creating direct reply receiver ' . $e->getMessage(), DEBUG_CATCHS );
  317. }
  318. } //This is the normal case to fetch all receivers on groups, individuals, etc
  319. else { //THERE COULD BE A PROBLEM HERE IF notifications_receivers is empty, or other conditions default to "else" when its not expected
  320. try {
  321. self::logActions( 'process_notifications: Going through normal case', DEBUG_FULL );
  322. try {
  323. //search recipients
  324. $possible_students_tmp = array ();
  325. foreach ( $selectedReceivers ['people'] as $recipient => $userId ) {
  326. array_push( $allRecipients, $userId );
  327. array_push( $possible_students_tmp, $userId );
  328. }
  329. //Parents notifications on assignments, find possible parents for this users
  330. self::logActions( 'process_notifications: type ' . $messageData ['type'], DEBUG_FULL );
  331. if ($messageData ['type'] == 'assignment' || $messageData ['type'] == 'alert') {
  332. $parents_ids = ParentsStudents::getInstance()->getParentsForStudents( $possible_students_tmp, true );
  333. self::logActions( 'process_notifications: parent ids ' . print_r( $parents_ids, true ), DEBUG_FULL );
  334. $allRecipients = array_merge( $allRecipients, $parents_ids );
  335. }
  336. } catch ( exception $e ) {
  337. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  338. self::logActions( "\n" . 'process_notifications:ERROR with People array ' . $e->getMessage(), DEBUG_CATCHS );
  339. }
  340. try {
  341. //adds recipients from groups
  342. if (is_array( $selectedReceivers ['locations'] )) {
  343. foreach ( $selectedReceivers ['locations'] as $location ) {
  344. if ($location ['type'] == 'group') {
  345. $tmpUserIds = Groups::getInstance()->getGroupMembersToNotify( $location ['id'] );
  346. $tmpName = Groups::getInstance()->getGroup( $location ['id'], false, true );
  347. foreach ( $tmpUserIds as $user_id ) {
  348. array_push( $allRecipients, $user_id );
  349. array_push( $membersOfGroup, array ($user_id => $tmpName ['title'] ) );
  350. $messageData['parent_group_title'] = $tmpName['parent_group_title'];
  351. }
  352. //Parents notifications on assignments, find possible parents for this groups
  353. self::logActions( 'process_notifications: group type ' . $messageData ['type'], DEBUG_FULL );
  354. if ( $messageData ['type'] == 'assignment' || $messageData ['type'] == 'alert') {
  355. $parents_ids = ParentsStudents::getInstance()->getParents( $location ['id'], true );
  356. self::logActions( 'process_notifications: group parent ids ' . print_r( $parents_ids, true ), DEBUG_FULL );
  357. if (count( $parents_ids )) {
  358. foreach ( $parents_ids as $parent ) {
  359. array_push( $allRecipients, $parent ['parent_id'] );
  360. if (! array_key_exists( $parent ['parent_id'], $parentsOfGroup ))
  361. $parentsOfGroup [$parent ['parent_id']] = $tmpName ['title'];
  362. }
  363. }
  364. }
  365. }
  366. if ($location ['type'] == 'group_parents')
  367. {
  368. $tmpName = Groups::getInstance()->getGroup( $location ['id'] );
  369. //Parents notifications on assignments, find possible parents for this groups
  370. self::logActions( 'process_notifications: group type ' . $messageData ['type'], DEBUG_FULL );
  371. if ($messageData ['type'] == 'text' || $messageData ['type'] == 'comment' || $messageData ['type'] == 'assignment' || $messageData ['type'] == 'alert') {
  372. $parents_ids = ParentsStudents::getInstance()->getParents( $location ['id'], true );
  373. self::logActions( 'process_notifications: group parent ids ' . print_r( $parents_ids, true ), DEBUG_FULL );
  374. if (count( $parents_ids )) {
  375. foreach ( $parents_ids as $parent ) {
  376. array_push( $allRecipients, $parent ['parent_id'] );
  377. if (! array_key_exists( $parent ['parent_id'], $parentsOfGroup ))
  378. $parentsOfGroup [$parent ['parent_id']] = $tmpName ['title'];
  379. if (! array_key_exists( $parent ['parent_id'], $parentsGroups ))
  380. $parentsGroups [$parent ['parent_id']] = $location ['id'];
  381. }
  382. }
  383. }
  384. }
  385. if ($location ['type'] == 'all-groups')
  386. {
  387. $groups = Groups::getInstance()->getUserGroups($accountInfo['user_id'],false,false);
  388. foreach( $groups as $group)
  389. {
  390. if ($group['read_only'] == 1) {
  391. // Do not send email notifications to a group that the user
  392. // cannot post to.
  393. continue;
  394. }
  395. $group_id = $group['group_id'];
  396. $tmpUserIds = Groups::getInstance()->getGroupMembersToNotify( $group_id );
  397. $tmpName = Groups::getInstance()->getGroup( $group_id, false, true );
  398. foreach ( $tmpUserIds as $user_id ) {
  399. array_push( $allRecipients, $user_id );
  400. array_push( $membersOfGroup, array ($user_id => $tmpName ['title']) );
  401. $messageData['parent_group_title'] = $tmpName['parent_group_title'];
  402. }
  403. //Parents notifications on assignments, find possible parents for this groups
  404. self::logActions( 'process_notifications: group type ' . $messageData ['type'], DEBUG_FULL );
  405. if ( $messageData ['type'] == 'assignment' || $messageData ['type'] == 'alert') {
  406. $parents_ids = ParentsStudents::getInstance()->getParents( $location ['id'], true );
  407. self::logActions( 'process_notifications: group parent ids ' . print_r( $parents_ids, true ), DEBUG_FULL );
  408. if (count( $parents_ids )) {
  409. foreach ( $parents_ids as $parent ) {
  410. array_push( $allRecipients, $parent ['parent_id'] );
  411. if (! array_key_exists( $parent ['parent_id'], $parentsOfGroup ))
  412. $parentsOfGroup [$parent ['parent_id']] = $tmpName ['title'];
  413. }
  414. }
  415. }
  416. }
  417. }
  418. //Will add recipients from institution admins
  419. $inst_admins = array();
  420. if ($location ['type'] == 'school' || $location ['type'] == 'school_vip') {
  421. $inst_admins = Schools::getInstance()->getAllSchoolAdmins( $location ['id'] );
  422. $messageData['posted_in_school'] = 1;
  423. }
  424. if ($location ['type'] == 'district' || $location ['type'] == 'district_vip') {
  425. $inst_admins = Districts::getInstance()->getDistrictMembers( $location ['id'] ,false,'admins','',true);
  426. }
  427. foreach($inst_admins as $admin)
  428. {
  429. if(isset($admin['admin_notifications']) && !empty($admin['admin_notifications']))
  430. {
  431. array_push( $allRecipients, $admin ['user_id'] );
  432. array_push( $adminRecipients, $admin ['user_id'] );
  433. }
  434. }
  435. unset( $inst_admins );
  436. }
  437. foreach ( $parentsOfGroup as $key => $parent ) {
  438. self::logActions( 'process_notifications: group parents ' . print_r( array ($key => $parent ), true ), DEBUG_FULL );
  439. //we insert the parent as a member of the group to hack the subject behaviour
  440. array_push( $membersOfGroup, array ($key => $parent ) );
  441. }
  442. self::logActions( 'process_notifications: group members ' . print_r( $parentsOfGroup, true ), DEBUG_FULL );
  443. } else {
  444. self::logActions( '$selectedReceivers[\'locations\'] is not an array... Workflow ended unexpectedly', DEBUG_FULL );
  445. }
  446. } catch ( exception $e ) {
  447. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  448. self::logActions( "\n" . 'process_notifications:ERROR adding recipients from groups ' . $e->getMessage(), DEBUG_CATCHS );
  449. }
  450. } catch ( exception $e ) {
  451. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  452. self::logActions( "\n" . 'process_notifications:ERROR on Normal Case ' . $e->getMessage(), DEBUG_CATCHS );
  453. }
  454. }
  455. //removes repeated recipients
  456. $uniqueRecipients = array_unique( $allRecipients );
  457. } catch ( exception $e ) {
  458. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  459. self::logActions( "\n" . 'process_notifications:ERROR general recipients fail ' . $e->getMessage(), DEBUG_CATCHS );
  460. }
  461. //--------------------------------
  462. // Log some Data
  463. self::logActions( '$uniqueRecipients: ' . print_r( $uniqueRecipients, true ), DEBUG_FULL );
  464. self::logActions( '$membersOfGroup: ' . print_r( $membersOfGroup, true ), DEBUG_FULL );
  465. try {
  466. //check settings for recipients
  467. //PREVENT ERROR ON EMPTY ARRAY
  468. if(isset($uniqueRecipients) && !empty($uniqueRecipients) && count($uniqueRecipients) > 0)
  469. {
  470. $notificationsSettings = Notifications::getInstance()->getNotificationsForUsers( $uniqueRecipients );
  471. }
  472. else
  473. {
  474. $notificationsSettings = array();
  475. self::logActions( "\n" . 'process_notifications:ERROR: empty uniqueRecipients: ' , DEBUG_FULL);
  476. }
  477. } catch ( exception $e ) {
  478. //--------------------------------
  479. // Log the Exception
  480. self::logActions( "\n" . 'process_notifications:ERROR: on getNotificationsForUsers: ' . $e->getMessage(), DEBUG_CATCHS );
  481. $notificationsSettings = array ();
  482. }
  483. try {
  484. //check if incoming type is correct in db
  485. $tmpType = self::$typeMapping [$workerArray['message_data']['type']];
  486. //avoid joing group type
  487. if (self::isJoinGruoup( $messageData ) == false) {
  488. //call functions for notifications
  489. foreach ( $notificationsSettings as $notification ) {
  490. $recipientInfo = Users::getInstance()->getUserInfoWithSubdomain( $notification ['user_id'] );
  491. if ($recipientInfo['type'] == 'PARENT')
  492. {
  493. $recipientInfo['parent_groups'] = $parentsGroups;
  494. }
  495. $contents = self::prepareSubject( $messageData, $accountInfo, $recipientInfo, $membersOfGroup );
  496. $contents['group_id'] = $tmpName['group_id'];
  497. self::logActions( "\n" . 'Attempt to send with IF params: ' . $notification [$tmpType] . ' | ' . $accountInfo ['user_id'] . ' | ' . $notification ['user_id'], DEBUG_FULL);
  498. $contents['isDirect'] = self::isDirectMessage( $notification, $selectedReceivers );
  499. $is_admin_notification = self::isAdminNotification( $notification, $messageData, $adminRecipients );
  500. self::logActions( "\n" . 'adminRecipients ' . print_r($adminRecipients, true), DEBUG_FULL);
  501. //Will send if notification is valid and not admin, or is direct message, or admin settings are correct
  502. if ((($notification [$tmpType] == 1 && !in_array($notification['user_id'],$adminRecipients)) || $contents ['isDirect'] || $is_admin_notification) && ($accountInfo ['user_id'] != $notification ['user_id'])) {
  503. //call service notification func
  504. switch ($notification ['type']) {
  505. case 'TWITTER':
  506. self::postOnTwitter( $notification, $contents );
  507. break;
  508. case 'EMAIL':
  509. $messageData['is_admin_notification'] = $is_admin_notification;
  510. self::sendEmail( $contents, $recipientInfo, $messageData, $workerArray ['server_name'], $notification, $accountInfo );
  511. break;
  512. case 'SMS':
  513. self::sendSms( $notification, $contents, $recipientInfo );
  514. break;
  515. default :
  516. break;
  517. }
  518. }
  519. }
  520. } else {
  521. self::logActions( "\n" . 'Did not sent message - was join group', DEBUG_FULL );
  522. }
  523. } catch ( exception $e ) {
  524. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  525. self::logActions( "\n" . 'process_notifications:ERROR on for each notificationsSettings ' . $e->getMessage(), DEBUG_CATCHS );
  526. }
  527. self::logActions( "\n" . 'NotificationsWorker::Finished Logging' . "\n" . '-------------------------------' . "\n", DEBUG_CATCHS );
  528. self::writeLog();
  529. try {
  530. //Trying to free memory, cant do it outside here becuase reference is no good
  531. //unset seems to not force garbage collection according to the manual,
  532. $notificationsSettings = array ();
  533. $allRecipients = array ();
  534. $membersOfGroup = array ();
  535. self::$log = NULL;
  536. unset( $notificationsSettings );
  537. unset( $allRecipients );
  538. unset( $membersOfGroup );
  539. } catch ( exception $e ) {
  540. //EMPTY CATCH, CANT LOG ANYTHING HERE, LOGGING ERROR
  541. }
  542. }
  543. private function getSalutationName($recipient_language, $first_name, $last_name, $user_type, $title = 'NONE')
  544. {
  545. $registryKey = 'th-' . $recipient_language;
  546. if (Zend_Registry::isRegistered($registryKey)) {
  547. $translator = Zend_Registry::get($registryKey);
  548. } else {
  549. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'email-subjects.tmx', $recipient_language);
  550. Zend_Registry::set($registryKey, $translator);
  551. }
  552. $salutation_name = ucwords($first_name);
  553. switch($user_type)
  554. {
  555. case 'STUDENT':
  556. // if mbstring extension is installed, use it to handle multibyte strings
  557. if (function_exists('mb_substr')) {
  558. $last_initial = mb_substr($last_name, 0, 1, 'UTF-8');
  559. } else {
  560. $last_initial = substr($last_name, 0, 1);
  561. }
  562. $salutation_name = ucwords($first_name) . ' ' . strtoupper($last_initial) . '.';
  563. break;
  564. case 'TEACHER':
  565. $new_title = ($title == 'NONE') ? $first_name : $translator->_($title) . '.';
  566. $salutation_name = ucwords(strtolower($new_title)) . ' ' . ucwords($last_name);
  567. break;
  568. }
  569. return $salutation_name;
  570. }
  571. private function getSimpleSentTo($language, $recipient_id, $message_id, $message_recipients = null)
  572. {
  573. $to = null;
  574. if (!$message_recipients)
  575. {
  576. $message_recipients = Messages::getInstance()->getMessageRecipients($message_id);
  577. }
  578. foreach ($message_recipients as $recipient)
  579. {
  580. if ('group' == trim(ArrayHelper::elem($recipient, 'posted_in')))
  581. {
  582. if (UsersGroups::getInstance()->userIsMemberOfGroup($recipient_id, $recipient['posted_in_id']))
  583. {
  584. $group = Groups::getInstance()->find($recipient['posted_in_id'])->current()->toArray();
  585. $to = ArrayHelper::elem($group, 'title');
  586. }
  587. }
  588. if ($to)
  589. {
  590. break;
  591. }
  592. }
  593. $registryKey = 'th-' . $recipient_language;
  594. if (Zend_Registry::isRegistered($registryKey)) {
  595. $translator = Zend_Registry::get($registryKey);
  596. } else {
  597. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'email-subjects.tmx', $recipient_language);
  598. Zend_Registry::set($registryKey, $translator);
  599. }
  600. if ($to)
  601. {
  602. $to = $translator->_('reply-to-group') . ' ' . $to;
  603. }
  604. else
  605. {
  606. $to = $translator->_('reply-to-you');
  607. }
  608. return $to;
  609. }
  610. /**
  611. * Prepares the content of the message with correct title, subject, and language
  612. * @param array $messageData the info of the original sent message
  613. * @param array $senderInfo information from the sender
  614. * @param array $destinationInfo information for this destination
  615. * @return array the subject, first line, and content of the message
  616. */
  617. private function prepareSubject($messageData, $senderInfo, $destinationInfo, $membersOfGroup) {
  618. $retSubject = '';
  619. $senderTitle = '';
  620. $replied = '';
  621. $bodyText = '';
  622. $links_text = '';
  623. $replied_to = '';
  624. $replied_to_type = '';
  625. $other_reply_count = 0;
  626. $other_reply_count_text = '';
  627. try {
  628. $registryKey = 'th-' . $destinationInfo['language'];
  629. if (Zend_Registry::isRegistered($registryKey)) {
  630. $translator = Zend_Registry::get($registryKey);
  631. } else {
  632. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'email-subjects.tmx', $destinationInfo['language']);
  633. Zend_Registry::set($registryKey, $translator);
  634. }
  635. $senderTitle = ucwords($senderInfo['first_name']);
  636. //Sender Title
  637. if ($senderInfo['type'] == 'STUDENT') {
  638. // if mbstring extension is installed, use it to handle multibyte strings
  639. if (function_exists('mb_substr')) {
  640. $last_initial = mb_substr($senderInfo['last_name'], 0, 1, 'UTF-8');
  641. } else {
  642. $last_initial = substr($senderInfo['last_name'], 0, 1);
  643. }
  644. $firstLine = ucwords( $senderInfo ['first_name'] ) . ' ' . strtoupper( $last_initial );
  645. $senderTitle = $firstLine . '.';
  646. }
  647. if ($senderInfo ['type'] == 'TEACHER') {
  648. $displayTitle = (!$senderInfo ['title'] || $senderInfo ['title'] == 'NONE') ? $senderInfo ['first_name'] . ' ' : $translator->_( $senderInfo ['title'] ) . '. ';
  649. $firstLine = ucwords( strtolower( $displayTitle ) ) . ucwords( $senderInfo ['last_name'] );
  650. $senderTitle = $firstLine;
  651. }
  652. $possibleGroupName = self::checkGroupArray($destinationInfo, $membersOfGroup);
  653. //subject
  654. if ($messageData['comment_to'] != NULL) {
  655. $other_reply_count = ArrayHelper::elem($messageData, 'other_reply_count', 0);
  656. if ($other_reply_count > 0)
  657. {
  658. if ($other_reply_count == 1)
  659. {
  660. $other_reply_count_text = $translator->_('one-more-reply');
  661. }
  662. else
  663. {
  664. $other_reply_count_text = $other_reply_count . ' ' . $translator->_('multiple-more-replies');
  665. }
  666. }
  667. $commentToInfo = Messages::getInstance()->getMessageInfo($messageData['comment_to']);
  668. $commentToType = $commentToInfo['type'];
  669. $replied_to_a = $translator->_('replied-to-a');
  670. $replied_to_type = $translator->_('direct-' . $commentToType);
  671. $retSubject = $senderTitle . " " . $replied_to_a . $translator->_('direct-' . $commentToType);
  672. self::logActions('prepareSubject: The type is ' . $commentToType . ' subject: ' . $retSubject . "\n", DEBUG_FULL);
  673. } else if ($possibleGroupName != false) {
  674. $groupName = $possibleGroupName;
  675. //modifyng subject on assigments for parents, they come as members of the group
  676. if ($destinationInfo ['type'] == 'PARENT' && ($messageData ['type'] == 'assignment' || $messageData ['type'] == 'alert' || $messageData ['type'] == 'text' || $messageData ['type'] == 'comment')) {
  677. if(isset($destinationInfo['parent_groups']) && count($destinationInfo['parent_groups']) > 0)
  678. {
  679. $group_id = $destinationInfo['parent_groups'][$destinationInfo['user_id']];
  680. $student_ids = ParentsStudents::getInstance()->getParentStudentsByGroup($destinationInfo['user_id'],$group_id);
  681. }
  682. else
  683. {
  684. $students_info = ParentsHandler::getInstance()->getParentStudentsInfo( $destinationInfo );
  685. $student_ids = $students_info ['student_ids'];
  686. }
  687. $groupName = MessagingHelper::getInstance()->addChildrensNames( $groupName, $student_ids); //$destinationInfo['language']
  688. self::logActions('prepareSubject: group Name ' . $groupName . "\n", DEBUG_FULL);
  689. }
  690. $retSubject = $senderTitle . " " . $translator->_('sent-a') . $translator->_('direct-' . $messageData['type']) . " " . $translator->_('to') . " " . $groupName;
  691. } else {
  692. $retSubject = $senderTitle . " " . $translator->_( 'sent-you-a' ) . $translator->_( 'direct-' . $messageData ['type'] );
  693. }
  694. self::logActions( 'prepareSubject: subject: ' . $retSubject, DEBUG_FULL );
  695. $replied = ($messageData ['comment_to'] == NULL) ? '' : ' ' . $translator->_('replied');
  696. //body
  697. switch($messageData ['type'])
  698. {
  699. case 'assignment' :
  700. $bodyText = $messageData ['assignment'];
  701. break;
  702. case 'quiz' :
  703. $bodyText = $messageData ['quiz_title'];
  704. break;
  705. case 'poll':
  706. $bodyText = $messageData ['poll_question'];
  707. break;
  708. default:
  709. $msg = $messageData ['message'];
  710. if (strpos( $msg, 'new-group:' ) !== false) {
  711. $grp_id = str_replace( 'new-group:', '', $msg );
  712. $grp_info = Groups::getInstance()->getGroup( $grp_id );
  713. $msg = $translator->_( 'you-created-the-group' ) . " " . $grp_info ['title'] . "\n" . $translator->_( 'the-group-code-is' ) . " " . $grp_info ['code'];
  714. }
  715. $bodyText = MessagingHelper::formatDBString($msg,true,true,false,true);
  716. //self::logActions( "\n" . 'TEXT: ' . $bodyText, DEBUG_FULL );
  717. break;
  718. }
  719. if ($messageData['type'] == 'text' && isset( $messageData['links']) && is_array($messageData['links'])) {
  720. $links_text = '';
  721. foreach ( $messageData['links'] as $link ) {
  722. if (!isset($link['type']) || $link['type'] != 'embed') {
  723. $link_title = trim($link['desc']);
  724. $link_title = ($link_title && !filter_var($link_title, FILTER_VALIDATE_URL) ? $link_title : 'Link');
  725. if(LinkHandler::isEdmodoPostUrl($link['url']))
  726. {
  727. if(strpos($link_title,'Edmodo | Where Learning Happens') === false)
  728. {
  729. $links_text .= $link_title ;
  730. }
  731. else
  732. {
  733. $link_title = $translator->_( 'edmodo-post' );
  734. $links_text .= "<a href='{$link['url']}'>{$link_title}</a>\n";
  735. }
  736. }
  737. else
  738. {
  739. $links_text .= "<a href='{$link['url']}'>{$link_title}</a>\n";
  740. }
  741. }
  742. }
  743. }
  744. } catch ( exception $e ) {
  745. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  746. self::logActions( "\n" . 'prepareSubject: processing subject ' . $e->getMessage(), DEBUG_CATCHS );
  747. }
  748. $emailContents = array ('subject' => $retSubject, 'sender_title' => $senderTitle, 'first-line' => $senderTitle . $replied . ':', 'content' => $bodyText, 'links_text' => $links_text, 'replied_to_a' => $replied_to_a, 'replied_to_type' => $replied_to_type, 'other_reply_count' => $other_reply_count, 'other_reply_count_text' => $other_reply_count_text, 'group_name' => $groupName);
  749. return $emailContents;
  750. }
  751. private function formatMessageLink($contents, $messageData, $language, $recipientInfo, $serverName) {
  752. try {
  753. $formattedLink = MailHandler::getInstance()->formatEmailUrl($serverName, $recipientInfo, $messageData);
  754. self::logActions( "\n" . 'formatMessageLink: recipientInfo ' . print_r( $recipientInfo, true ), DEBUG_FULL );
  755. } catch ( exception $e ) {
  756. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  757. self::logActions( "\n" . 'formatMessageLink: formatting server name ' . $e->getMessage(), DEBUG_CATCHS );
  758. }
  759. $spotlightType = '';
  760. $registryKey='th-'.$language;
  761. if(false && Zend_Registry::isRegistered($registryKey)){
  762. $translator=Zend_Registry::get($registryKey);
  763. }else{
  764. // $translator = new TranslationHelper( new Zend_Translate( 'tmx', PATH2_LANGUAGES . 'email-subjects.tmx', $language ) );
  765. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'email-subjects.tmx', 'en');
  766. $englishType = $translator->_('link-' . $messageData['type']);
  767. $translator = TranslationHelper::getInstance(PATH2_LANGUAGES . 'email-subjects.tmx', $language);
  768. Zend_Registry::set($registryKey, $translator);
  769. }
  770. $translatedType = $translator->_( 'link-' . $messageData ['type'] );
  771. try {
  772. self::logActions( "\n" . 'formatMessageLink: Will format: ' . $contents ['isDirect'] . ' type: ' . $messageData ['type'] . ' comment-to: ' . $messageData ['comment_to'], DEBUG_FULL );
  773. if ($messageData ['comment_to'] != NULL) {
  774. $formattedLink .= '/post/' . $messageData ['comment_to'];
  775. $translatedType = $translator->_( 'comment-to' );
  776. } else if (!empty($messageData ['message_id'])) {
  777. $formattedLink .= '/post/' . $messageData ['message_id'];
  778. }
  779. else {
  780. //No spotlight type, just go to home
  781. $formattedLink .= '';
  782. }
  783. } catch ( exception $e ) {
  784. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  785. self::logActions( "\n" . 'formatMessageLink: formatting link ' . $e->getMessage(), DEBUG_CATCHS );
  786. }
  787. $formattedArray = array(
  788. 'formattedLink' => $formattedLink,
  789. 'translatedType' => $translatedType,
  790. 'type' => $englishType,
  791. );
  792. self::logActions( "\n Formated Link: \n" . $formattedLink, DEBUG_FULL );
  793. return $formattedArray;
  794. }
  795. /**
  796. * Searches for the group name for a user that belongs to that group
  797. * @param array $destinationInfo the info for the user to search
  798. * @param array $membersOfGroup ids from all users members to this group
  799. * @return string group Name or false
  800. */
  801. private function checkGroupArray($destinationInfo, $membersOfGroup) {
  802. $answer = false;
  803. try {
  804. foreach ( $membersOfGroup as $key => $member ) {
  805. if (array_key_exists( $destinationInfo ['user_id'], $member )) {
  806. $answer = $member [$destinationInfo ['user_id']];
  807. break;
  808. }
  809. }
  810. } catch ( exception $e ) {
  811. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  812. self::logActions( "\n" . 'checkGroupArray:ERROR on for each membersOfGroup ' . $e->getMessage(), DEBUG_CATCHS );
  813. }
  814. return $answer;
  815. }
  816. /**
  817. * current way of knowing if a message is from "joining a group"
  818. * @param array $messageData the info for the user to search
  819. * @return boolean if message is of type "join group"
  820. */
  821. private function isJoinGruoup($messageData) {
  822. $answer = false;
  823. if ($messageData ['type'] == 'system') {
  824. if (stristr( $messageData ['message'], 'joined' ) && stristr( $messageData ['message'], 'group' ))
  825. $answer = true;
  826. }
  827. return $answer;
  828. }
  829. //Checks if a user is an admin and has the right settings to receive notifications
  830. private function isAdminNotification($notification, $message_data, $admin_recipients)
  831. {
  832. $is_admin = false;
  833. if(!empty($notification['admin_notifications']))
  834. {
  835. if(!empty($notification['admin_notes']) && $message_data['type'] == 'text' && in_array($notification['user_id'],$admin_recipients))
  836. {
  837. $is_admin = true;
  838. }
  839. if(!empty($notification['admin_replies']) && $message_data['type'] == 'comment' && in_array($notification['user_id'],$admin_recipients))
  840. {
  841. $is_admin = true;
  842. }
  843. self::logActions( "\n isAdminNotification::$is_admin ,admin_notes: " . $notification['admin_notes'] ." admin_replies: " . $notification['admin_replies'] . " type: " . $message_data['type'] . " \n" , DEBUG_FULL );
  844. }
  845. return $is_admin;
  846. }
  847. /**
  848. * Determines if a user needs to receive a direct message
  849. * @param arra…

Large files files are truncated, but you can click here to view the full file