PageRenderTime 65ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/woka.php

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

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