start.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. /**
  3. * Provides links and notifications for using @username mentions
  4. *
  5. */
  6. elgg_register_event_handler('init', 'system', 'mentions_init');
  7. function mentions_init() {
  8. elgg_extend_view('css/elgg', 'css/mentions');
  9. elgg_require_js('mentions/autocomplete');
  10. elgg_extend_view('input/longtext', 'mentions/popup');
  11. elgg_extend_view('input/plaintext', 'mentions/popup');
  12. elgg_register_event_handler('pagesetup', 'system', 'mentions_get_views');
  13. // can't use notification hooks here because of many reasons
  14. elgg_register_event_handler('create', 'object', 'mentions_notification_handler');
  15. elgg_register_event_handler('create', 'annotation', 'mentions_notification_handler');
  16. // @todo This will result in multiple notifications for an edited entity so we don't do this
  17. //register_elgg_event_handler('update', 'all', 'mentions_notification_handler');
  18. // add option to the personal notifications form
  19. elgg_extend_view('notifications/subscriptions/personal', 'mentions/notification_settings');
  20. elgg_register_plugin_hook_handler('action', 'notificationsettings/save', 'mentions_save_settings');
  21. }
  22. function mentions_get_regex() {
  23. // @todo this won't work for usernames that must be html encoded.
  24. // get all chars with unicode 'letter' or 'mark' properties or a number _ or .,
  25. // preceeded by @, and possibly surrounded by word boundaries.
  26. return '/[\b]?@([\p{L}\p{M}_\.0-9]+)[\b]?/iu';
  27. }
  28. function mentions_get_views() {
  29. // allow plugins to add additional views to be processed for usernames
  30. $views = array('output/longtext');
  31. $views = elgg_trigger_plugin_hook('get_views', 'mentions', null, $views);
  32. foreach ($views as $view) {
  33. elgg_register_plugin_hook_handler('view', $view, 'mentions_rewrite');
  34. }
  35. }
  36. /**
  37. * Rewrites a view for @username mentions.
  38. *
  39. * @param string $hook The name of the hook
  40. * @param string $type The type of the hook
  41. * @param string $content The content of the page
  42. * @return string
  43. */
  44. function mentions_rewrite($hook, $entity_type, $returnvalue, $params) {
  45. $regexp = mentions_get_regex();
  46. $returnvalue = preg_replace_callback($regexp, 'mentions_preg_callback', $returnvalue);
  47. return $returnvalue;
  48. }
  49. /**
  50. * Used as a callback fro the preg_replace in mentions_rewrite()
  51. *
  52. * @param type $matches
  53. * @return type str
  54. */
  55. function mentions_preg_callback($matches) {
  56. $user = get_user_by_username($matches[1]);
  57. $period = '';
  58. $icon = '';
  59. // Catch the trailing period when used as punctuation and not a username.
  60. if (!$user && substr($matches[1], -1) == '.') {
  61. $user = get_user_by_username(rtrim($matches[1], '.'));
  62. $period = '.';
  63. }
  64. if ($user) {
  65. if (elgg_get_plugin_setting('fancy_links', 'mentions')) {
  66. $icon = elgg_view('output/img', array(
  67. 'src' => $user->getIconURL('topbar'),
  68. 'class' => 'pas mentions-user-icon'
  69. ));
  70. $replace = elgg_view('output/url', array(
  71. 'href' => $user->getURL(),
  72. 'text' => $icon . $user->name,
  73. 'class' => 'mentions-user-link'
  74. ));
  75. } else {
  76. $replace = elgg_view('output/url', array(
  77. 'href' => $user->getURL(),
  78. 'text' => $user->name,
  79. ));
  80. }
  81. return $replace .= $period;
  82. } else {
  83. return $matches[0];
  84. }
  85. }
  86. /**
  87. * Catch all create events and scan for @username tags to notify user.
  88. *
  89. * @param string $event The event name
  90. * @param string $event_type The event type
  91. * @param ElggData $object The object that was created
  92. * @return void
  93. */
  94. function mentions_notification_handler($event, $event_type, $object) {
  95. // excludes messages - otherwise an endless loop of notifications occur!
  96. if (elgg_instanceof($object, 'object', 'messages')) {
  97. return;
  98. }
  99. $type = $object->getType();
  100. $subtype = $object->getSubtype();
  101. $owner = $object->getOwnerEntity();
  102. $fields = array(
  103. 'title', 'description', 'value'
  104. );
  105. // store the guids of notified users so they only get one notification per creation event
  106. $notified_guids = array();
  107. foreach ($fields as $field) {
  108. $content = $object->$field;
  109. // it's ok in this case if 0 matches == FALSE
  110. if (preg_match_all(mentions_get_regex(), $content, $matches)) {
  111. // match against the 2nd index since the first is everything
  112. foreach ($matches[1] as $username) {
  113. $user = get_user_by_username($username);
  114. // check for trailing punctuation caught by the regex
  115. if (!$user && substr($username, -1) == '.') {
  116. $user = get_user_by_username(rtrim($username, '.'));
  117. }
  118. if (!$user) {
  119. continue;
  120. }
  121. // user must have access to view object/annotation
  122. if ($type == 'annotation') {
  123. $annotated_entity = $object->getEntity();
  124. if (!$annotated_entity || !has_access_to_entity($annotated_entity, $user)) {
  125. continue;
  126. }
  127. } else {
  128. if (!has_access_to_entity($object, $user)) {
  129. continue;
  130. }
  131. }
  132. if (!in_array($user->getGUID(), $notified_guids)) {
  133. $notified_guids[] = $user->getGUID();
  134. // if they haven't set the notification status default to sending.
  135. // Private settings are stored as strings so we check against "0"
  136. $notification_setting = elgg_get_plugin_user_setting('notify', $user->getGUID(), 'mentions');
  137. if ($notification_setting === "0") {
  138. continue;
  139. }
  140. $link = $object->getURL();
  141. $type_key = "mentions:notification_types:$type:$subtype";
  142. $type_str = elgg_echo($type_key);
  143. if ($type_str == $type_key) {
  144. // plugins can add to the list of mention objects by defining
  145. // the language string 'mentions:notification_types:<type>:<subtype>'
  146. continue;
  147. }
  148. $subject = elgg_echo('mentions:notification:subject', array($owner->name, $type_str));
  149. $body = elgg_echo('mentions:notification:body', array(
  150. $owner->name,
  151. $type_str,
  152. $link,
  153. ));
  154. $params = array(
  155. 'object' => $object,
  156. 'action' => 'mention',
  157. );
  158. notify_user($user->getGUID(), $owner->getGUID(), $subject, $body, $params);
  159. }
  160. }
  161. }
  162. }
  163. }
  164. /**
  165. * Save mentions-specific info from the notification form
  166. *
  167. * @param type $hook
  168. * @param type $type
  169. * @param type $value
  170. * @param type $params
  171. */
  172. function mentions_save_settings($hook, $type, $value, $params) {
  173. $notify = (bool) get_input('mentions_notify');
  174. $user = get_entity(get_input('guid'));
  175. if (!elgg_set_plugin_user_setting('notify', $notify, $user->getGUID(), 'mentions')) {
  176. register_error(elgg_echo('mentions:settings:failed'));
  177. }
  178. return;
  179. }