notification.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. <?php
  2. /**
  3. * Adding a New Notification Event
  4. * ===============================
  5. * 1. Register the event with elgg_register_notification_event()
  6. *
  7. * 2. Register for the notification message plugin hook:
  8. * 'prepare', 'notification:[event name]'. The event name is of the form
  9. * [action]:[type]:[subtype]. For example, the publish event for a blog
  10. * would be named 'publish:object:blog'.
  11. *
  12. * The parameter array for the plugin hook has the keys 'event', 'method',
  13. * 'recipient', and 'language'. The event is an \Elgg\Notifications\Event
  14. * object and can provide access to the original object of the event through
  15. * the method getObject() and the original actor through getActor().
  16. *
  17. * The plugin hook callback modifies and returns a
  18. * \Elgg\Notifications\Notification object that holds the message content.
  19. *
  20. *
  21. * Adding a Delivery Method
  22. * =========================
  23. * 1. Register the delivery method name with elgg_register_notification_method()
  24. *
  25. * 2. Register for the plugin hook for sending notifications:
  26. * 'send', 'notification:[method name]'. It receives the notification object
  27. * of the namespace Elgg\Notifications;
  28. class Notification in the params array with the
  29. * key 'notification'. The callback should return a boolean to indicate whether
  30. * the message was sent.
  31. *
  32. *
  33. * Subscribing a User for Notifications
  34. * ====================================
  35. * Users subscribe to receive notifications based on container and delivery method.
  36. *
  37. *
  38. * @package Elgg.Core
  39. * @subpackage Notifications
  40. */
  41. /**
  42. * Register a notification event
  43. *
  44. * Elgg sends notifications for the items that have been registered with this
  45. * function. For example, if you want notifications to be sent when a bookmark
  46. * has been created or updated, call the function like this:
  47. *
  48. * elgg_register_notification_event('object', 'bookmarks', array('create', 'update'));
  49. *
  50. * @param string $object_type 'object', 'user', 'group', 'site'
  51. * @param string $object_subtype The subtype or name of the entity
  52. * @param array $actions Array of actions or empty array for the action event.
  53. * An event is usually described by the first string passed
  54. * to elgg_trigger_event(). Examples include
  55. * 'create', 'update', and 'publish'. The default is 'create'.
  56. * @return void
  57. * @since 1.9
  58. */
  59. function elgg_register_notification_event($object_type, $object_subtype, array $actions = array()) {
  60. _elgg_services()->notifications->registerEvent($object_type, $object_subtype, $actions);
  61. }
  62. /**
  63. * Unregister a notification event
  64. *
  65. * @param string $object_type 'object', 'user', 'group', 'site'
  66. * @param string $object_subtype The type of the entity
  67. * @return bool
  68. * @since 1.9
  69. */
  70. function elgg_unregister_notification_event($object_type, $object_subtype) {
  71. return _elgg_services()->notifications->unregisterEvent($object_type, $object_subtype);
  72. }
  73. /**
  74. * Register a delivery method for notifications
  75. *
  76. * Register for the 'send', 'notification:[method name]' plugin hook to handle
  77. * sending a notification. A notification object is in the params array for the
  78. * hook with the key 'notification'. See \Elgg\Notifications\Notification.
  79. *
  80. * @param string $name The notification method name
  81. * @return void
  82. * @see elgg_unregister_notification_method()
  83. * @since 1.9
  84. */
  85. function elgg_register_notification_method($name) {
  86. _elgg_services()->notifications->registerMethod($name);
  87. }
  88. /**
  89. * Unregister a delivery method for notifications
  90. *
  91. * @param string $name The notification method name
  92. * @return bool
  93. * @see elgg_register_notification_method()
  94. * @since 1.9
  95. */
  96. function elgg_unregister_notification_method($name) {
  97. return _elgg_services()->notifications->unregisterMethod($name);
  98. }
  99. /**
  100. * Subscribe a user to notifications about a target entity
  101. *
  102. * @param int $user_guid The GUID of the user to subscribe to notifications
  103. * @param string $method The delivery method of the notifications
  104. * @param int $target_guid The entity to receive notifications about
  105. * @return bool
  106. * @since 1.9
  107. */
  108. function elgg_add_subscription($user_guid, $method, $target_guid) {
  109. $methods = _elgg_services()->notifications->getMethods();
  110. $db = _elgg_services()->db;
  111. $subs = new \Elgg\Notifications\SubscriptionsService($db, $methods);
  112. return $subs->addSubscription($user_guid, $method, $target_guid);
  113. }
  114. /**
  115. * Unsubscribe a user to notifications about a target entity
  116. *
  117. * @param int $user_guid The GUID of the user to unsubscribe to notifications
  118. * @param string $method The delivery method of the notifications to stop
  119. * @param int $target_guid The entity to stop receiving notifications about
  120. * @return bool
  121. * @since 1.9
  122. */
  123. function elgg_remove_subscription($user_guid, $method, $target_guid) {
  124. $methods = _elgg_services()->notifications->getMethods();
  125. $db = _elgg_services()->db;
  126. $subs = new \Elgg\Notifications\SubscriptionsService($db, $methods);
  127. return $subs->removeSubscription($user_guid, $method, $target_guid);
  128. }
  129. /**
  130. * Get the subscriptions for the content created inside this container.
  131. *
  132. * The return array is of the form:
  133. *
  134. * array(
  135. * <user guid> => array('email', 'sms', 'ajax'),
  136. * );
  137. *
  138. * @param int $container_guid GUID of the entity acting as a container
  139. * @return array User GUIDs (keys) and their subscription types (values).
  140. * @since 1.9
  141. * @todo deprecate once new subscriptions system has been added
  142. */
  143. function elgg_get_subscriptions_for_container($container_guid) {
  144. $methods = _elgg_services()->notifications->getMethods();
  145. $db = _elgg_services()->db;
  146. $subs = new \Elgg\Notifications\SubscriptionsService($db, $methods);
  147. return $subs->getSubscriptionsForContainer($container_guid);
  148. }
  149. /**
  150. * Queue a notification event for later handling
  151. *
  152. * Checks to see if this event has been registered for notifications.
  153. * If so, it adds the event to a notification queue.
  154. *
  155. * This function triggers the 'enqueue', 'notification' hook.
  156. *
  157. * @param string $action The name of the action
  158. * @param string $type The type of the object
  159. * @param \ElggData $object The object of the event
  160. * @return void
  161. * @access private
  162. * @since 1.9
  163. */
  164. function _elgg_enqueue_notification_event($action, $type, $object) {
  165. _elgg_services()->notifications->enqueueEvent($action, $type, $object);
  166. }
  167. /**
  168. * @access private
  169. */
  170. function _elgg_notifications_cron() {
  171. // calculate when we should stop
  172. // @todo make configurable?
  173. $stop_time = time() + 45;
  174. _elgg_services()->notifications->processQueue($stop_time);
  175. }
  176. /**
  177. * Send an email notification
  178. *
  179. * @param string $hook Hook name
  180. * @param string $type Hook type
  181. * @param bool $result Has anyone sent a message yet?
  182. * @param array $params Hook parameters
  183. * @return bool
  184. * @access private
  185. */
  186. function _elgg_send_email_notification($hook, $type, $result, $params) {
  187. /* @var \Elgg\Notifications\Notification $message */
  188. $message = $params['notification'];
  189. $sender = $message->getSender();
  190. $recipient = $message->getRecipient();
  191. if (!$sender) {
  192. return false;
  193. }
  194. if (!$recipient || !$recipient->email) {
  195. return false;
  196. }
  197. $to = $recipient->email;
  198. $site = elgg_get_site_entity();
  199. // If there's an email address, use it - but only if it's not from a user.
  200. if (!($sender instanceof \ElggUser) && $sender->email) {
  201. $from = $sender->email;
  202. } else if ($site->email) {
  203. $from = $site->email;
  204. } else {
  205. // If all else fails, use the domain of the site.
  206. $from = 'noreply@' . $site->getDomain();
  207. }
  208. return elgg_send_email($from, $to, $message->subject, $message->body, $params);
  209. }
  210. /**
  211. * Adds default thread SMTP headers to group messages correctly.
  212. * Note that it won't be sufficient for some email clients. Ie. Gmail is looking at message subject anyway.
  213. *
  214. * @param string $hook Equals to 'email'
  215. * @param string $type Equals to 'system'
  216. * @param array $returnvalue Array containing fields: 'to', 'from', 'subject', 'body', 'headers', 'params'
  217. * @param array $params The same value as $returnvalue
  218. * @return array
  219. * @access private
  220. */
  221. function _elgg_notifications_smtp_thread_headers($hook, $type, $returnvalue, $params) {
  222. $notificationParams = elgg_extract('params', $returnvalue, array());
  223. /** @var \Elgg\Notifications\Notification */
  224. $notification = elgg_extract('notification', $notificationParams);
  225. if (!($notification instanceof \Elgg\Notifications\Notification)) {
  226. return $returnvalue;
  227. }
  228. $hostname = parse_url(elgg_get_site_url(), PHP_URL_HOST);
  229. $urlPath = parse_url(elgg_get_site_url(), PHP_URL_PATH);
  230. $object = elgg_extract('object', $notification->params);
  231. /** @var \Elgg\Notifications\Event $event */
  232. $event = elgg_extract('event', $notification->params);
  233. if (($object instanceof \ElggEntity) && ($event instanceof \Elgg\Notifications\Event)) {
  234. if ($event->getAction() === 'create') {
  235. // create event happens once per entity and we need to guarantee message id uniqueness
  236. // and at the same time have thread message id that we don't need to store
  237. $messageId = "<{$urlPath}.entity.{$object->guid}@{$hostname}>";
  238. } else {
  239. $mt = microtime(true);
  240. $messageId = "<{$urlPath}.entity.{$object->guid}.$mt@{$hostname}>";
  241. }
  242. $returnvalue['headers']["Message-ID"] = $messageId;
  243. $container = $object->getContainerEntity();
  244. // let's just thread comments by default
  245. if (($container instanceof \ElggEntity) && ($object instanceof \ElggComment)) {
  246. $threadMessageId = "<{$urlPath}.entity.{$container->guid}@{$hostname}>";
  247. $returnvalue['headers']['In-Reply-To'] = $threadMessageId;
  248. $returnvalue['headers']['References'] = $threadMessageId;
  249. }
  250. }
  251. return $returnvalue;
  252. }
  253. /**
  254. * @access private
  255. */
  256. function _elgg_notifications_init() {
  257. elgg_register_plugin_hook_handler('cron', 'minute', '_elgg_notifications_cron', 100);
  258. elgg_register_event_handler('all', 'all', '_elgg_enqueue_notification_event');
  259. // add email notifications
  260. elgg_register_notification_method('email');
  261. elgg_register_plugin_hook_handler('send', 'notification:email', '_elgg_send_email_notification');
  262. elgg_register_plugin_hook_handler('email', 'system', '_elgg_notifications_smtp_thread_headers');
  263. // add ability to set personal notification method
  264. elgg_extend_view('forms/account/settings', 'core/settings/account/notifications');
  265. elgg_register_plugin_hook_handler('usersettings:save', 'user', '_elgg_save_notification_user_settings');
  266. }
  267. /**
  268. * Notify a user via their preferences.
  269. *
  270. * @param mixed $to Either a guid or an array of guid's to notify.
  271. * @param int $from GUID of the sender, which may be a user, site or object.
  272. * @param string $subject Message subject.
  273. * @param string $message Message body.
  274. * @param array $params Misc additional parameters specific to various methods.
  275. * @param mixed $methods_override A string, or an array of strings specifying the delivery
  276. * methods to use - or leave blank for delivery using the
  277. * user's chosen delivery methods.
  278. *
  279. * @return array Compound array of each delivery user/delivery method's success or failure.
  280. * @access private
  281. */
  282. function _elgg_notify_user($to, $from, $subject, $message, array $params = null, $methods_override = "") {
  283. $notify_service = _elgg_services()->notifications;
  284. // Sanitise
  285. if (!is_array($to)) {
  286. $to = array((int)$to);
  287. }
  288. $from = (int)$from;
  289. //$subject = sanitise_string($subject);
  290. // Get notification methods
  291. if (($methods_override) && (!is_array($methods_override))) {
  292. $methods_override = array($methods_override);
  293. }
  294. $result = array();
  295. foreach ($to as $guid) {
  296. // Results for a user are...
  297. $result[$guid] = array();
  298. if ($guid) { // Is the guid > 0?
  299. // Are we overriding delivery?
  300. $methods = $methods_override;
  301. if (!$methods) {
  302. $tmp = get_user_notification_settings($guid);
  303. $methods = array();
  304. // $tmp may be false. don't cast
  305. if (is_object($tmp)) {
  306. foreach ($tmp as $k => $v) {
  307. // Add method if method is turned on for user!
  308. if ($v) {
  309. $methods[] = $k;
  310. }
  311. }
  312. }
  313. }
  314. if ($methods) {
  315. // Deliver
  316. foreach ($methods as $method) {
  317. $handler = $notify_service->getDeprecatedHandler($method);
  318. /* @var callable $handler */
  319. if (!$handler || !is_callable($handler)) {
  320. elgg_log("No handler registered for the method $method", 'WARNING');
  321. continue;
  322. }
  323. elgg_log("Sending message to $guid using $method");
  324. // Trigger handler and retrieve result.
  325. try {
  326. $result[$guid][$method] = call_user_func($handler,
  327. $from ? get_entity($from) : null,
  328. get_entity($guid),
  329. $subject,
  330. $message,
  331. $params
  332. );
  333. } catch (Exception $e) {
  334. error_log($e->getMessage());
  335. }
  336. }
  337. }
  338. }
  339. }
  340. return $result;
  341. }
  342. /**
  343. * Notifications
  344. * This file contains classes and functions which allow plugins to register and send notifications.
  345. *
  346. * There are notification methods which are provided out of the box
  347. * (see notification_init() ). Each method is identified by a string, e.g. "email".
  348. *
  349. * To register an event use register_notification_handler() and pass the method name and a
  350. * handler function.
  351. *
  352. * To send a notification call notify() passing it the method you wish to use combined with a
  353. * number of method specific addressing parameters.
  354. *
  355. * Catch NotificationException to trap errors.
  356. *
  357. * @package Elgg.Core
  358. * @subpackage Notifications
  359. */
  360. /**
  361. * Notify a user via their preferences.
  362. *
  363. * @param mixed $to Either a guid or an array of guid's to notify.
  364. * @param int $from GUID of the sender, which may be a user, site or object.
  365. * @param string $subject Message subject.
  366. * @param string $message Message body.
  367. * @param array $params Misc additional parameters specific to various methods.
  368. *
  369. * By default Elgg core supports three parameters, which give
  370. * notification plugins more control over the notifications:
  371. *
  372. * object => null|\ElggEntity|\ElggAnnotation The object that
  373. * is triggering the notification.
  374. *
  375. * action => null|string Word that describes the action that
  376. * is triggering the notification (e.g. "create"
  377. * or "update").
  378. *
  379. * summary => null|string Summary that notification plugins
  380. * can use alongside the notification title and body.
  381. *
  382. * @param mixed $methods_override A string, or an array of strings specifying the delivery
  383. * methods to use - or leave blank for delivery using the
  384. * user's chosen delivery methods.
  385. *
  386. * @return array Compound array of each delivery user/delivery method's success or failure.
  387. * @throws NotificationException
  388. */
  389. function notify_user($to, $from, $subject, $message, array $params = array(), $methods_override = "") {
  390. if (!is_array($to)) {
  391. $to = array((int)$to);
  392. }
  393. $from = (int)$from;
  394. $from = get_entity($from) ? $from : elgg_get_site_entity()->guid;
  395. $sender = get_entity($from);
  396. $summary = elgg_extract('summary', $params, '');
  397. // Get notification methods
  398. if (($methods_override) && (!is_array($methods_override))) {
  399. $methods_override = array($methods_override);
  400. }
  401. $result = array();
  402. $available_methods = _elgg_services()->notifications->getMethods();
  403. if (!$available_methods) {
  404. // There are no notifications methods to use
  405. return $result;
  406. }
  407. // temporary backward compatibility for 1.8 and earlier notifications
  408. $event = null;
  409. if (isset($params['object']) && isset($params['action'])) {
  410. $event = new \Elgg\Notifications\Event($params['object'], $params['action'], $sender);
  411. }
  412. $params['event'] = $event;
  413. foreach ($to as $guid) {
  414. // Results for a user are...
  415. $result[$guid] = array();
  416. if ($guid) { // Is the guid > 0?
  417. // Are we overriding delivery?
  418. $methods = $methods_override;
  419. if (!$methods) {
  420. $tmp = (array)get_user_notification_settings($guid);
  421. $methods = array();
  422. foreach ($tmp as $k => $v) {
  423. // Add method if method is turned on for user!
  424. if ($v) {
  425. $methods[] = $k;
  426. }
  427. }
  428. }
  429. if ($methods) {
  430. // Deliver
  431. foreach ($methods as $method) {
  432. if (!in_array($method, $available_methods)) {
  433. // This method was available the last time the user saved their
  434. // notification settings. It's however currently disabled.
  435. continue;
  436. }
  437. if (_elgg_services()->hooks->hasHandler('send', "notification:$method")) {
  438. // 1.9 style notification handler
  439. $recipient = get_entity($guid);
  440. if (!$recipient) {
  441. continue;
  442. }
  443. $language = $recipient->language;
  444. $notification = new \Elgg\Notifications\Notification($sender, $recipient, $language, $subject, $message, $summary, $params);
  445. $params['notification'] = $notification;
  446. $result[$guid][$method] = _elgg_services()->hooks->trigger('send', "notification:$method", $params, false);
  447. } else {
  448. $result[$guid][$method] = _elgg_notify_user($guid, $from, $subject, $message, $params, array($method));
  449. }
  450. }
  451. }
  452. }
  453. }
  454. return $result;
  455. }
  456. /**
  457. * Get the notification settings for a given user.
  458. *
  459. * @param int $user_guid The user id
  460. *
  461. * @return \stdClass|false
  462. */
  463. function get_user_notification_settings($user_guid = 0) {
  464. $user_guid = (int)$user_guid;
  465. if ($user_guid == 0) {
  466. $user_guid = elgg_get_logged_in_user_guid();
  467. }
  468. // @todo: there should be a better way now that metadata is cached. E.g. just query for MD names, then
  469. // query user object directly
  470. $all_metadata = elgg_get_metadata(array(
  471. 'guid' => $user_guid,
  472. 'limit' => 0
  473. ));
  474. if ($all_metadata) {
  475. $prefix = "notification:method:";
  476. $return = new \stdClass;
  477. foreach ($all_metadata as $meta) {
  478. $name = substr($meta->name, strlen($prefix));
  479. $value = $meta->value;
  480. if (strpos($meta->name, $prefix) === 0) {
  481. $return->$name = $value;
  482. }
  483. }
  484. return $return;
  485. }
  486. return false;
  487. }
  488. /**
  489. * Set a user notification pref.
  490. *
  491. * @param int $user_guid The user id.
  492. * @param string $method The delivery method (eg. email)
  493. * @param bool $value On(true) or off(false).
  494. *
  495. * @return bool
  496. */
  497. function set_user_notification_setting($user_guid, $method, $value) {
  498. $user_guid = (int)$user_guid;
  499. $method = sanitise_string($method);
  500. $user = get_entity($user_guid);
  501. if (!$user) {
  502. $user = elgg_get_logged_in_user_entity();
  503. }
  504. if (($user) && ($user instanceof \ElggUser)) {
  505. $prefix = "notification:method:$method";
  506. $user->$prefix = $value;
  507. $user->save();
  508. return true;
  509. }
  510. return false;
  511. }
  512. /**
  513. * Send an email to any email address
  514. *
  515. * @param string $from Email address or string: "name <email>"
  516. * @param string $to Email address or string: "name <email>"
  517. * @param string $subject The subject of the message
  518. * @param string $body The message body
  519. * @param array $params Optional parameters (none used in this function)
  520. *
  521. * @return bool
  522. * @throws NotificationException
  523. * @since 1.7.2
  524. */
  525. function elgg_send_email($from, $to, $subject, $body, array $params = null) {
  526. global $CONFIG;
  527. if (!$from) {
  528. $msg = "Missing a required parameter, '" . 'from' . "'";
  529. throw new \NotificationException($msg);
  530. }
  531. if (!$to) {
  532. $msg = "Missing a required parameter, '" . 'to' . "'";
  533. throw new \NotificationException($msg);
  534. }
  535. $headers = array(
  536. "Content-Type" => "text/plain; charset=UTF-8; format=flowed",
  537. "MIME-Version" => "1.0",
  538. "Content-Transfer-Encoding" => "8bit",
  539. );
  540. // return true/false to stop elgg_send_email() from sending
  541. $mail_params = array(
  542. 'to' => $to,
  543. 'from' => $from,
  544. 'subject' => $subject,
  545. 'body' => $body,
  546. 'headers' => $headers,
  547. 'params' => $params,
  548. );
  549. // $mail_params is passed as both params and return value. The former is for backwards
  550. // compatibility. The latter is so handlers can now alter the contents/headers of
  551. // the email by returning the array
  552. $result = elgg_trigger_plugin_hook('email', 'system', $mail_params, $mail_params);
  553. if (is_array($result)) {
  554. foreach (array('to', 'from', 'subject', 'body', 'headers') as $key) {
  555. if (isset($result[$key])) {
  556. ${$key} = $result[$key];
  557. }
  558. }
  559. } elseif ($result !== null) {
  560. return $result;
  561. }
  562. $header_eol = "\r\n";
  563. if (isset($CONFIG->broken_mta) && $CONFIG->broken_mta) {
  564. // Allow non-RFC 2822 mail headers to support some broken MTAs
  565. $header_eol = "\n";
  566. }
  567. // Windows is somewhat broken, so we use just address for to and from
  568. if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
  569. // strip name from to and from
  570. if (strpos($to, '<')) {
  571. preg_match('/<(.*)>/', $to, $matches);
  572. $to = $matches[1];
  573. }
  574. if (strpos($from, '<')) {
  575. preg_match('/<(.*)>/', $from, $matches);
  576. $from = $matches[1];
  577. }
  578. }
  579. // make sure From is set
  580. if (empty($headers['From'])) {
  581. $headers['From'] = $from;
  582. }
  583. // stringify headers
  584. $headers_string = '';
  585. foreach ($headers as $key => $value) {
  586. $headers_string .= "$key: $value{$header_eol}";
  587. }
  588. // Sanitise subject by stripping line endings
  589. $subject = preg_replace("/(\r\n|\r|\n)/", " ", $subject);
  590. // this is because Elgg encodes everything and matches what is done with body
  591. $subject = html_entity_decode($subject, ENT_QUOTES, 'UTF-8'); // Decode any html entities
  592. if (is_callable('mb_encode_mimeheader')) {
  593. $subject = mb_encode_mimeheader($subject, "UTF-8", "B");
  594. }
  595. // Format message
  596. $body = html_entity_decode($body, ENT_QUOTES, 'UTF-8'); // Decode any html entities
  597. $body = elgg_strip_tags($body); // Strip tags from message
  598. $body = preg_replace("/(\r\n|\r)/", "\n", $body); // Convert to unix line endings in body
  599. $body = preg_replace("/^From/", ">From", $body); // Change lines starting with From to >From
  600. $body = wordwrap($body);
  601. return mail($to, $subject, $body, $headers_string);
  602. }
  603. /**
  604. * Save personal notification settings - input comes from request
  605. *
  606. * @return void
  607. * @access private
  608. */
  609. function _elgg_save_notification_user_settings() {
  610. $method = get_input('method');
  611. $current_settings = get_user_notification_settings();
  612. $result = false;
  613. foreach ($method as $k => $v) {
  614. // check if setting has changed and skip if not
  615. if ($current_settings->$k == ($v == 'yes')) {
  616. continue;
  617. }
  618. $result = set_user_notification_setting(elgg_get_logged_in_user_guid(), $k, ($v == 'yes') ? true : false);
  619. if (!$result) {
  620. register_error(elgg_echo('notifications:usersettings:save:fail'));
  621. }
  622. }
  623. if ($result) {
  624. system_message(elgg_echo('notifications:usersettings:save:ok'));
  625. }
  626. }
  627. /**
  628. * @access private
  629. */
  630. function _elgg_notifications_test($hook, $type, $tests) {
  631. global $CONFIG;
  632. $tests[] = "{$CONFIG->path}engine/tests/ElggCoreDatabaseQueueTest.php";
  633. return $tests;
  634. }
  635. return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
  636. $events->registerHandler('init', 'system', '_elgg_notifications_init');
  637. $hooks->registerHandler('unit_test', 'system', '_elgg_notifications_test');
  638. };