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