PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/work.php

https://github.com/blakeparkinson/dumbgame
PHP | 1596 lines | 1209 code | 190 blank | 197 comment | 276 complexity | 82d49cd2986b0713334a07dce1e389b3 MD5 | raw 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 array $notification the users notifications settings
  850. * @param array $selectedReceivers receivers for the message
  851. * @return boolean if should receive the direct message
  852. */
  853. private function isDirectMessage($notification, $selectedReceivers) {
  854. $sendDirect = false;
  855. try {
  856. if ($notification ['messages'] == 1) {
  857. if (isset( $selectedReceivers ['people'] ) && is_array( $selectedReceivers ['people'] )) {
  858. if (in_array( $notification ['user_id'], $selectedReceivers ['people'] )) {
  859. //if messages flag is on, and user is in the "people" list
  860. $sendDirect = true;
  861. self::logActions( "\n" . 'Is Direct Message, should deliver message: ' . self::$msgID . ' to user: ' . $notification ['user_id'] . "\n", DEBUG_FULL );
  862. } else
  863. self::logActions( "\n" . 'isDirectMessage:Not in receivers ', DEBUG_FULL );
  864. } else
  865. self::logActions( "\n" . 'isDirectMessage:selectedReceivers[people] failed ', DEBUG_FULL );
  866. } else
  867. self::logActions( "\n" . 'isDirectMessage:Notification off ' . $notification ['messages'] . "\n", DEBUG_FULL );
  868. } catch ( exception $e ) {
  869. self::logActions( "\n" . 'FAILURE: MSGID: ' . self::$msgID . ', MSGTYPE: ' . self::$msgType, DEBUG_CATCHS );
  870. self::logActions( "\n" . 'isDirectMessage:ERROR checking for direct notification ' . $e->getMessage(), DEBUG_CATCHS );
  871. }
  872. return $sendDirect;
  873. }
  874. /**
  875. * Sends a message on twitter, truncates it to appropiate length
  876. * @param array $usrSettings info for the receiver
  877. * @param array $contents the message contents
  878. * @return
  879. */
  880. private function postOnTwitter($usrSettings, $contents) {
  881. try {
  882. $tw = TwitterHelper::getInstance();
  883. $message = $tw->truncate( $contents ['first-line'] . ' ' . $contents ['content'], '' );
  884. $response = $tw->sendDirectMessage( $usrSettings ['via'], $message );
  885. self::logActions( 'Sending a Twitter notification to <' . $usrSettings ['via'] . '> status: ' . ($response ? 'SUCCESS' : 'FAILURE'), DEBUG_FULL );
  886. } catch ( exception $e ) {
  887. self::logActions( "\n" . 'postOnTwitter: ERROR: An Exception was thrown: ' . $e->getMessage(), DEBUG_CATCHS );
  888. }
  889. }
  890. private static function simpleTruncate($string, $min_length, $max_length)
  891. {
  892. if (strlen($string) <= $max_length)
  893. {
  894. return $string;
  895. }
  896. $limiter = "CUTHERECUTHERECUTHERE";
  897. $string = wordwrap($string, $min_length, $limiter, true);
  898. $strings = explode($limiter, $string);
  899. return $strings[0] . '...';
  900. }
  901. /**
  902. * Sends the email message
  903. * @param array $contents the message contents
  904. * @param array $recipientInfo information for this destination
  905. * @param array $messageData - some data/information concerning the message
  906. * @param string $serverName - the box from which the email was trigger
  907. * @param array $user_settings - optional - email settings of the user
  908. * @param array $account_info - optional - account info of user sending the note
  909. * @return
  910. */
  911. private function sendEmail($contents, $recipientInfo, $messageData, $serverName, $user_settings = array(), $account_info = array()) {
  912. try {
  913. //rollout for the notifications fix to "send all" expected emails, hopefully we can remove this one very soon
  914. $notifications_fix = AbHandler::idInTest($recipientInfo['user_id'], 'notifications_fix_rollout');
  915. if($user_settings['email_verified'] == 1 || $notifications_fix != AbHandler::CONTROL)
  916. {
  917. $should_use_phtml = false;
  918. $misc_data_tracking = array();
  919. $language = $recipientInfo['language'];
  920. $messageLink = self::formatMessageLink($contents, $messageData, $language, $recipientInfo, $serverName);
  921. $use_new_replies = (NOTIFICATIONS_NEW_REPLIES_ALL_ON == 1);
  922. if (!$use_new_replies && NOTIFICATIONS_NEW_REPLIES_GATED_ON == 1)
  923. {
  924. $tests = AbTestingHandler::getTestsByUserId($recipientInfo['user_id']);
  925. foreach ($tests as $test)
  926. {
  927. if (StringHelper::beginsWith($test, NOTIFICATIONS_NEW_REPLIES_GATE_PREFIX))
  928. {
  929. $use_new_replies = true;
  930. break;
  931. }
  932. }
  933. }
  934. if (NOTIFICATIONS_NEW_REPLIES_FORCE_OFF == 1)
  935. {
  936. $use_new_replies = false;
  937. }
  938. if ($use_new_replies)
  939. {
  940. $data = array(
  941. 'message_id' => null,
  942. 'message_info' => null,
  943. 'message_sender_info' => null,
  944. 'message_recipients' => null,
  945. 'message_to' => null,
  946. 'message_content' => null,
  947. 'message_from_salutation' => null,
  948. 'reply_id' => null,
  949. 'reply_sender_info' => null,
  950. 'reply_from_salutation' => null,
  951. );
  952. $is_reply = (trim($messageLink['translatedType']) == 'reply');
  953. if ($is_reply)
  954. {
  955. $template_name = TrackingHelper::EMAILTYPE_NOTIFICATIONS_3;
  956. $data['message_id'] = $messageData['comment_to'];
  957. $data['reply_id'] = $messageData['comment_id'];
  958. }
  959. else
  960. {
  961. $template_name = TrackingHelper::EMAILTYPE_NOTIFICATIONS_2;
  962. $data['message_id'] = $messageData['message_id'];
  963. }
  964. $data['message_info'] = Messages::getInstance()->getMessageInfo($data['message_id']);
  965. $data['message_sender_info'] = Messages::getInstance()->getSenderInfoByMessageId($data['message_id']);
  966. $data['message_recipients'] = Messages::getInstance()->getMessageRecipients($data['message_id']);
  967. $data['message_from_salutation'] = self::getSalutationName($recipientInfo['language'], $data['message_sender_info']['first_name'], $data['message_sender_info']['last_name'], $data['message_sender_info']['type'], $data['message_sender_info']['title']);
  968. $data['message_to'] = self::getSimpleSentTo($recipientInfo['language'], $recipientInfo['user_id'], $data['message_id'], $data['message_recipients']);
  969. // reply to message
  970. if ($is_reply)
  971. {
  972. $data['message_content'] = Messages::getInstance()->getMessageContent($data['message_id'], $data['message_info']['type']);
  973. $data['reply_content'] = $contents['content'];
  974. $data['reply_from_salutation'] = $contents['sender_title'];
  975. $values2insert = array (
  976. '{MESSAGE_FULLNAME}' => $data['message_from_salutation'],
  977. '{MESSAGE_SENT_TO}' => $data['message_to'],
  978. '{MESSAGE_NOTIFICATION}' => self::simpleTruncate($data['message_content'], 95, 100),
  979. '{MESSAGE_TYPE}' => $contents['replied_to_type'],
  980. '{MESSAGE_LINK}' => $messageLink['formattedLink'],
  981. '{COMMENT_FULLNAME}' => $data['reply_from_salutation'],
  982. '{COMMENT_NOTIFICATION}' => self::simpleTruncate($contents['content'], 495, 500),
  983. '{COMMENT_TYPE}' => ucfirst(trim($messageLink['translatedType'])),
  984. '{COMMENT_COUNT_TEXT}' => $contents['other_reply_count_text'],
  985. );
  986. $contents['subject'] = $data['reply_from_salutation'] . ' ' . $contents['replied_to_a'] . $contents['replied_to_type'] . ' ' . $data['message_to'];
  987. }
  988. else // original message
  989. {
  990. $data['message_content'] = $contents['content'];
  991. $data['message_from_salutation'] = $contents['sender_title'];
  992. $values2insert = array (
  993. '{MESSAGE_FULLNAME}' => $data['message_from_salutation'],
  994. '{MESSAGE_SENT_TO}' => $data['message_to'],
  995. '{MESSAGE_NOTIFICATION}' => $contents['content'],
  996. '{MESSAGE_LINKS_TEXT}' => $contents['links_text'],
  997. '{MESSAGE_TYPE}' => $messageLink['translatedType'],
  998. '{MESSAGE_LINK}' => $messageLink['formattedLink'],
  999. );
  1000. }
  1001. }
  1002. else{
  1003. if ($messageData['type'] == 'text'){
  1004. //TODO if ab test is successful, these checks can be moved to a helper method
  1005. $should_use_phtml = true;
  1006. //get the profile url of the person sending the note
  1007. $profile_url = $recipientInfo['type'] == 'TEACHER' ? ENVIROMENT_DOMAIN.'/home#/profile/'.$account_info['user_id'] : ENVIROMENT_DOMAIN.'/home#/user?uid='.$account_info['user_id'];
  1008. //set template to the new ab email template
  1009. $template_name = TrackingHelper::EMAILTYPE_NOTIFICATIONS_5;
  1010. //build out email subject line depending on whether or not the email was sent to a group or not
  1011. $group_name = $contents['group_name'];
  1012. if (!empty($group_name)){
  1013. if (!empty($messageData['parent_group_title'])){
  1014. $group_name = $messageData['parent_group_title'];
  1015. }
  1016. $title_html = '<a href="'.$profile_url.'" style="color: #2ba6cb; text-decoration: none;">'.$contents['sender_title'].'</a> sent a<strong>'.$messageLink['translatedType'].'</strong> to <a href="'.ENVIROMENT_DOMAIN.'/home#/group?id='.$contents['group_id'].'" style="color: #2ba6cb; text-decoration: none;">'.$contents['group_name'].'</a>';
  1017. $footer_html = '<p style="padding:10px 0 10px 0;">You are receiving this email because you are subscribed to posts on <a href="'.ENVIROMENT_DOMAIN.'/home#/group?id='.$contents['group_id'].'" style="color: #2ba6cb; text-decoration: none;">'.$group_name.'</a>.</p>';
  1018. }
  1019. else{
  1020. $title_html = '<a href="'.$profile_url.'" style="color: #2ba6cb; text-decoration: none;">'.$contents['sender_title'].'</a> sent you a <strong>'.$messageLink['translatedType'].'</strong>';
  1021. $footer_html = '<p style="padding:10px 0 10px 0;">You are receiving this email because you are subscribed to direct posts.</p>';
  1022. }
  1023. $avatar_url = Profiles::getInstance()->getAvatarUrl($account_info['user_id'], $account_info['username'], 'AVATAR');
  1024. //grab the url of the first link and let's try to render a preview image of of that url
  1025. if (!empty($messageData['links'][0]['url'])){
  1026. $links_thumb = array();
  1027. $count_links = count($messageData['links']);
  1028. if ($count_links == 2){
  1029. $attachment_text = "<b>" .$count_links . '</b> attachments';
  1030. }
  1031. elseif ($count_links == 1){
  1032. $attachment_text = "<b>" .$count_links . '</b> attachment';
  1033. }
  1034. else{
  1035. $additional_attachments = $count_links - 2;
  1036. if ($additional_attachments == 1){
  1037. $word = 'attachment';
  1038. }
  1039. else{
  1040. $word = 'attachments';
  1041. }
  1042. $attachment_text = '<a href="'.$messageLink['formattedLink'].'"> Show '.$additional_attachments .' more ' .$word;
  1043. }
  1044. $i = 0;
  1045. $attachment_html = array();
  1046. foreach ($messageData['links'] as $link){
  1047. $parsed_url = trim($link['url'], '/');
  1048. if (!preg_match('#^http(s)?://#', $parsed_url)) {
  1049. $parsed_url = 'http://' . $parsed_url;
  1050. }
  1051. $urlParts = parse_url($parsed_url);
  1052. // remove www
  1053. $domain = preg_replace('/^www\./', '', $urlParts['host']);
  1054. if ($i < 2){
  1055. //first let's check to see if the webpage has open graph tags and grab it
  1056. $open_graph_info = OpenGraphHelper::fetch($link['url']);
  1057. $links_thumb[$i] = $open_graph_info->image;
  1058. //we couldn't get the open graph image, let's try to grab it from ShrinkTheWeb
  1059. if (empty($open_graph_info->image)){
  1060. //sleep and give ShrinkTheWeb some time to generate the preview link thumb
  1061. sleep(30);
  1062. $link_info = Links::getInstance()->getMessagesLinks($messageData['message_id']);
  1063. $stw_generated_thumb = $link_info[$i]['thumb_url'];
  1064. if (!empty($stw_generated_thumb)){
  1065. $links_thumb[$i] = THUMBS_SERVER.$stw_generated_thumb;
  1066. }
  1067. else{
  1068. //set a default image if we still don't have one. Worse case scenario. oh well
  1069. $links_thumb[$i] = PIC_SERVER.'default_155_2.jpg';
  1070. }
  1071. }
  1072. $attachment_html[] = '<table width="540" cellpadding="0" cellspacing="0" border="0" align="center" class="devicewidthinner" style="border-top:1px solid rgb(194, 198, 197); border-bottom: 1px solid rgb(194, 198, 197);">
  1073. <tbody>
  1074. <tr>
  1075. <td valign="middle" width="82" style="padding: 0px 20px 0px 20px;" class="link_tmb">
  1076. <br />
  1077. <div class="imgpop">
  1078. <a href="'.$link['url'].'"><img src="'.$links_thumb[$i].'" alt="'.$link['desc'].'" border="0" style="border-radius:3px;display:block; border:none; outline:none; text-decoration:none;" st-image="edit" class="link_tmb" width="82" height="62"></a>
  1079. </div>
  1080. <br />
  1081. </td>
  1082. <td width="458" valign="middle" style="font-family: Helvetica, Arial, sans-serif;font-size: 15px; color: #2b2e38;line-height: 24px; padding: 0px 20px 0px 0px;" align="left" class="txtpad">
  1083. <a href="'.$link['url'].'" style="text-align: left;font-family: Helvetica, Arial, sans-serif; font-size: 15px;line-height: 24px; font-weight:bold; text-decoration: none;" class="primaryLink">
  1084. '.$link['desc'].'</a><br />
  1085. <a href="#" class="secondaryLink">'.$domain.'</a>
  1086. </td>
  1087. </tr>
  1088. </tbody>
  1089. </table>';
  1090. }
  1091. else{
  1092. break;
  1093. }
  1094. $i++;
  1095. }
  1096. }
  1097. //build out an additional tracking array to so that we can track the ab test results. There are two running tests which can potentially collide so let's just put them both in the json string
  1098. $misc_data_tracking = array(TrackingHelper::MISCELLANEOUS_DATA_AB_TEST => array(TrackingHelper::MISCELLANEOUS_DATA_AB_TEST_NAME => 'notifications_link_email, ', TrackingHelper::MISCELLANEOUS_DATA_AB_TEST_VARIANT => $notifications_test_name));
  1099. $attachment_html = implode('', $attachment_html);
  1100. }
  1101. //set default subject
  1102. $subject = $contents['subject'];
  1103. //use default format of sender
  1104. $sender_str = "Edmodo";
  1105. if ($messageData['type'] == 'text' || $messageData['type'] == 'alert'){
  1106. $test_subject_line_gate = AbHandler::idInTest($recipientInfo['district_id'], 'notifications_subject_line_gate');
  1107. //make sure all eDistrict users are in the test, other users will take test if he/she is in the randomized bucket.
  1108. if ($test_subject_line_gate !== 'CONTROL'){
  1109. $test_subject_line = $test_subject_line_gate;
  1110. }else{
  1111. $test_subject_line = AbHandler::idInTest($recipientInfo['user_id'], 'notifications_subject_line');
  1112. }
  1113. $misc_data_tracking[TrackingHelper::MISCELLANEOUS_DATA_AB_TEST][TrackingHelper::MISCELLANEOUS_DATA_AB_TEST2_NAME] = 'notifications_subject_line';
  1114. $misc_data_tracking[TrackingHelper::MISCELLANEOUS_DATA_AB_TEST][TrackingHelper::MISCELLANEOUS_DATA_AB_TEST2_VARIANT] = $test_subject_line;
  1115. switch ($test_subject_line){
  1116. case 'sub1'://do the test if it is Alert
  1117. if ($messageData['type'] == 'alert'){
  1118. $subject = self::getTestSubject('alert',$contents,$recipientInfo,$account_info);
  1119. $sender_str = self::prepareEmailSender($account_info);
  1120. }
  1121. break;
  1122. case 'sub5'://do the test if it is Note
  1123. if ($messageData['type'] == 'text'){
  1124. $subject = self::getTestSubject('text',$contents,$recipientInfo,$account_info);
  1125. $sender_str = self::prepareEmailSender($account_info);
  1126. }
  1127. break;
  1128. case 'sub1_sub5'://do the test
  1129. $subject = self::getTestSubject($messageData['type'],$contents,$recipientInfo,$account_info);
  1130. $sender_str = self::prepareEmailSender($account_info);
  1131. break;
  1132. }
  1133. }
  1134. $values2insert = array (
  1135. '{LINK}' => $messageLink['formattedLink'],
  1136. '{TYPE}' => $messageLink['translatedType'],
  1137. '{SENDER}' => $contents['first-line'],
  1138. '{NOTIFICATION}' => $contents['content'],
  1139. '{LINKS_TEXT}' => $contents['links_text'],
  1140. '{SPACER}' => '',
  1141. '{GROUP_NAME}' => $contents['group_name'],
  1142. '{GROUP_URL}' => ENVIROMENT_DOMAIN.'/home#/group?id='.$contents['group_id'],
  1143. '{SENDER_PIC}' => isset($avatar_url) ? $avatar_url : null,
  1144. '{LINKS_THUMB}' => isset($links_thumb) ? $links_thumb : null,
  1145. '{LINKS_HEIGHT}' => isset($links_thumb) ? 62 : 0,
  1146. '{LINKS_TOP_SPACING}' => isset($links_thumb) ? 20 : 0,
  1147. '{LINKS_BOTTOM_SPACING}'=> isset($links_thumb) ? 15 : 0,
  1148. '{LINKS_WIDTH}' => isset($links_thumb) ? 82 : 0,
  1149. '{TITLE}' => isset($title_html) ? $title_html : null,
  1150. '{FOOTER}' => isset($footer_html) ? $footer_html : null,
  1151. '{SENDER_PROFILE_URL}' => isset($profile_url) ? $profile_url : null,
  1152. '{CONTENT_LINK}' => isset($messageData['links'][0]['url']) ? $messageData['links'][0]['url'] : null,
  1153. '{CTA_BUTTON}' => isset($cta_btn) ? $cta_btn : null,
  1154. '{SUBJECT}' => $subject,
  1155. '{ATTACHMENT_TEXT}' => isset($attachment_text) ? $attachment_text : '',
  1156. '{ATTACHMENT_HTML}' => isset($attachment_html) ? $attachment_html : null,
  1157. '{SEND_DATE}' => $currentDate = date("F j, Y"),
  1158. );
  1159. }
  1160. $body_text = MailHandler::getEmailTemplate($template_name, $language, '', $should_use_phtml);
  1161. $recipients = array (array ('email' => $recipientInfo['email'], 'username' => $recipientInfo ['username'] ) );
  1162. $emailValidator = new Zend_Validate_EmailAddress();
  1163. if ($emailValidator->isValid($recipientInfo['email'])) {
  1164. $mail_handler = new MailHandler($body_text);
  1165. $tracking_data = TrackingHelper::makeTrackingData($template_name, $messageLink['type'], null, TrackingHelper::TYPE_SYSTEM, $recipientInfo['user_id'], TrackingHelper::TYPE_USER, $recipientInfo['email'], self::$msgID, TrackingHelper::TYPE_MESSAGE, null, $messageData[TrackingHelper::DATA_DATE_REQUESTED], $misc_data_tracking);
  1166. $response = $mail_handler->setTrackingData($tracking_data)->sendEmailWrapper( $recipients, $subject, $values2insert, self::$replyTo, $sender_str, self::$replyTo, 'UTF-8',true );
  1167. unset( $mail_handler );
  1168. self::logActions( 'Sending an Email notification to <' . $recipientInfo ['email'] . '> status: ' . ($response ? 'SUCCESS' : 'FAILURE'), 2 );
  1169. } else {
  1170. self::logActions( 'Unable to send an Email notification to <' . $recipientInfo ['email'] . '> The email is invalid', DEBUG_FULL );
  1171. }
  1172. }
  1173. else
  1174. {
  1175. ActionsTracking::getInstance()->insert(array(
  1176. ActionsTrackingConstants::USER_AGENT => getenv('HTTP_USER_AGENT'),
  1177. ActionsTrackingConstants::EVENT_TYPE => 'notification-email',
  1178. ActionsTrackingConstants::EVENT_NAME => 'not-sent',
  1179. 'recipient_uid' => $recipientInfo ['user_id'],
  1180. 'recipient_email' => $recipientInfo ['email'],
  1181. 'template_name' => 'Notifications',
  1182. 'notification_type' => $messageData ['type']
  1183. ));
  1184. }
  1185. } catch ( exception $e ) {
  1186. self::logActions( "\n" . 'sendEmail: ERROR: An Exception was thrown: ' . $e->getMessage(), DEBUG_CATCHS);
  1187. }
  1188. }
  1189. /**
  1190. * format email sender info
  1191. * @param account_info array
  1192. * @return string
  1193. */
  1194. private function prepareEmailSender($account_info)
  1195. {
  1196. $sender = ucfirst($account_info['first_name']).' '.ucfirst($account_info['last_name']).' via Edmodo';
  1197. return $sender;
  1198. }
  1199. /**
  1200. * Truncated subject line
  1201. * @param content as string
  1202. * @param old_subject as string
  1203. * @return string
  1204. */
  1205. private function prepareTruncatedSubjectLine($content, $old_subject)
  1206. {
  1207. //wipe out any wacky characters in the subject line
  1208. $content = str_replace("<br />"," ",$content);
  1209. $subject = strip_tags(html_entity_decode($content, ENT_QUOTES));
  1210. if (strlen($subject) > 84){
  1211. $spliced_subject = substr($subject, 0, 82);
  1212. $subject = $spliced_subject . '...';
  1213. }
  1214. return $subject;
  1215. }
  1216. /**
  1217. * Prepare subject based on different abtest variants
  1218. * @param array $contents the message contents
  1219. * @param array $recipientInfo information for this destination
  1220. * @param array $account_info - optional - account info of user sending the note
  1221. * @return subject as string
  1222. */
  1223. private function getTestSubject($msg_type,$contents,$recipientInfo,$account_info)
  1224. {
  1225. $subject = $contents['subject'];
  1226. $subject_body = self::prepareTruncatedSubjectLine($contents['content'],$subject);
  1227. if (!empty($contents['group_name']) && $recipientInfo['type'] == 'PARENT'){
  1228. $student_id = ParentsStudents::getInstance()->getParentStudentsByGroup($recipientInfo['user_id'], $contents['group_id']);
  1229. if (count($student_id) == 1){
  1230. $student_info = Users::getInstance()->getUserInfo($student_id[0]);
  1231. }
  1232. if (!empty($student_info['first_name'])){
  1233. $group_first_name_position = strpos($contents['group_name'], '(' . $student_info['first_name'] . ')');
  1234. $spliced_parent_group_name = substr($contents['group_name'], 0, $group_first_name_position);
  1235. switch ($msg_type){
  1236. case 'alert':
  1237. $subject = '[' . $student_info['first_name'] .' - Alert to ' . $spliced_parent_group_name . '] ' . $subject_body;
  1238. break;
  1239. case 'text':
  1240. $subject = '[' . $student_info['first_name'] .' - ' . $spliced_parent_group_name . '] ' . $subject_body;
  1241. break;
  1242. }
  1243. }
  1244. else {
  1245. switch ($msg_type){
  1246. case 'alert':
  1247. $subject = 'Alert to ' . $contents['group_name'] . '] ' . $subject_body;
  1248. break;
  1249. case 'text':
  1250. $subject = '[' . $contents['group_name'] . '] ' . $subject_body;
  1251. break;
  1252. }
  1253. }
  1254. }
  1255. //alert through group with non-parent recipient
  1256. elseif (!empty($contents['group_name']) && $recipientInfo['type'] != 'PARENT'){
  1257. switch ($msg_type){
  1258. case 'alert':
  1259. $subject = '[Alert to ' . $contents['group_name'] . '] ' . $subject_body;
  1260. break;
  1261. case 'text':
  1262. $subject = '[' . $contents['group_name'] . '] ' . $subject_body;
  1263. break;
  1264. }
  1265. }
  1266. else{
  1267. switch ($msg_type){
  1268. case 'alert':
  1269. $subject = '[Alert]' . ' ' .$subject_body;
  1270. break;
  1271. case 'text':
  1272. $subject = $subject_body;
  1273. break;
  1274. }
  1275. }
  1276. return $subject;
  1277. }
  1278. /**
  1279. * Sends the SMS message, this is really an email using the phone carrier
  1280. * @param array $usrSettings the notification settings
  1281. * @param array $contents the message contents
  1282. * @param array $recipientInfo information for this destination
  1283. * @return array the subject, first line, and content of the message
  1284. */
  1285. private function sendSms($usrSettings, $contents, $recipientInfo) {
  1286. try {
  1287. if ($usrSettings ['phone_verified'] == 1) {
  1288. $message = $contents ['first-line'] . ' ' . $contents ['content'];
  1289. $carrier = PhoneCarriers::getInstance()->getCarrierInfo( $usrSettings ['phone_carrier_id'] );
  1290. $email = $usrSettings ['via'] . '@' . $carrier ['domain'];
  1291. $mail_handler = new MailHandler( $message );
  1292. $response = $mail_handler->sendSMS( $message, $email, $recipientInfo ['username'], self::$replyTo );
  1293. unset( $mail_handler );
  1294. if ($response) {
  1295. self::logActions( 'Sending an SMS notification to <' . $email . '> status: ' . ($response ? 'SUCCESS' : 'FAILURE'), DEBUG_FULL );
  1296. } else {
  1297. self::logActions( 'Unable to send an SMS notification to <' . $email . '> The email is invalid', DEBUG_FULL );
  1298. }
  1299. } else {
  1300. self::logActions( 'Unable to send an SMS notification to <' . $usrSettings ['via'] . '> The phone is not verified', DEBUG_FULL );
  1301. }
  1302. } catch ( exception $e ) {
  1303. self::logActions( "\n" . 'sendSMS: ERROR: An Exception was thrown: ' . $e->getMessage(), DEBUG_CATCHS );
  1304. }
  1305. }
  1306. /**
  1307. * Checks what level of DEBUG is on, and adds messages according to that
  1308. * @param string $entryLog the message to log
  1309. * @param int $level the Level to log: 0=No log, 1=Catch messages, 2=all info
  1310. * @return
  1311. */
  1312. private static function logActions($entryLog, $level = 0) {
  1313. if (GEARMAN_DEBUG && GEARMAN_DEBUG >= $level) {
  1314. self::$log .= '[' . date( 'd/M/Y:G:i:s O' ) . '] ' . $entryLog . "\n";
  1315. }
  1316. }
  1317. /**
  1318. * actually writes the log to a file
  1319. * @param string $nameAppend optional, to dinstinct the caller to the log: c = construct, d=destruct, e=email warning
  1320. * @return
  1321. */
  1322. private static function writeLog($nameAppend = '') {
  1323. //-------------------------
  1324. // Log the actions into a specific log file
  1325. try {
  1326. if (GEARMAN_DEBUG && GEARMAN_DEBUG > 0) {
  1327. $log_dir = '/tmp/gearman-logs';
  1328. if (! is_dir( $log_dir )) {
  1329. mkdir( $log_dir, 0777, true );
  1330. }
  1331. $logfile = $log_dir . '/send_notifications_' . $nameAppend . getmypid() . '.txt';
  1332. $handle = fopen( $logfile, 'a' );
  1333. if ($handle == FALSE) {
  1334. trigger_error( "unable to open file '$logfile'", E_USER_WARNING );
  1335. return FALSE;
  1336. }
  1337. fwrite( $handle, self::$log );
  1338. fclose( $handle );
  1339. self::$log = NULL;
  1340. //Should comment this? its ok, output is being sent to /dev/null
  1341. echo self::$log . "\n\n\n";
  1342. }
  1343. } catch ( exception $e ) {
  1344. trigger_error( $e->getMessage(), E_USER_WARNING );
  1345. }
  1346. }
  1347. /**
  1348. * Sends a warning email if code ever reaches where it sould not
  1349. * @return
  1350. */
  1351. private function sendWarningEmail() {
  1352. try {
  1353. $body_text = ' One of the Workers is down at http://www.' . ENVIROMENT_DOMAIN; //At the server name
  1354. /**
  1355. * this check is deprecated because groundwork can monitor processes and false alarms result when testing configurations- for now just email webops and jack
  1356. * @return
  1357. */
  1358. $recipients = array(
  1359. array (
  1360. 'email' => WEBOPS_EMAIL,
  1361. 'username' => 'WebOps',
  1362. ),
  1363. );
  1364. $mail_handler = new MailHandler( $body_text );
  1365. $tracking_data = TrackingHelper::makeTrackingData(TrackingHelper::EMAILTYPE_REPORT_A_BUG, null, null, TrackingHelper::TYPE_SYSTEM, null, TrackingHelper::TYPE_INTERNAL, WEBOPS_EMAIL);
  1366. $response = $mail_handler->setTrackingData($tracking_data)->sendEmailWrapper( $recipients, 'Urgent!', array (), SUPPORT_EMAIL, 'Gearman Worker', SUPPORT_EMAIL);
  1367. unset( $mail_handler );
  1368. } catch ( exception $e ) {
  1369. self::logActions( "\n" . ' ERROR: Sending Warning Email ' . $e->getMessage() . "\n", DEBUG_CATCHS );
  1370. self::writeLog( 'e_' );
  1371. }
  1372. }
  1373. /**
  1374. * Ensures that a minumum number of workers are always running.
  1375. * The amount of workers is controlled by the expected workers variable on appplication.ini
  1376. */
  1377. public static function watchAndRaiseWorkers() {
  1378. //count how many workers are running
  1379. $cmd = "ps -C php -F| grep " . basename( __FILE__ );
  1380. exec( $cmd, $output, $return_var );
  1381. $runningworkers = count( $output );
  1382. if ($runningworkers < self::$expectedWorkersNumber) { // if not enough workers are running then start more
  1383. // start N workers
  1384. for($i = 0; $i < self::$expectedWorkersNumber - $runningworkers; $i ++) {
  1385. self::logActions( "starting worker", DEBUG_FULL );
  1386. exec( 'nohup php NotificationsWorker.php > /dev/null 2>&1 &' );
  1387. }
  1388. }
  1389. }
  1390. function sig_handler($signo) {
  1391. switch ($signo) {
  1392. case SIGTERM :
  1393. // do any cleanup
  1394. $this->shutdown = TRUE;
  1395. self::logActions( "Recieved kill command", DEBUG_FULL );
  1396. self::writeLog();
  1397. exit( 0 );
  1398. }
  1399. }
  1400. }