start.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. <?php
  2. /**
  3. * Elgg internal messages plugin
  4. * This plugin lets users send messages to each other.
  5. *
  6. * @package ElggMessages
  7. */
  8. elgg_register_event_handler('init', 'system', 'messages_init');
  9. function messages_init() {
  10. // register a library of helper functions
  11. elgg_register_library('elgg:messages', elgg_get_plugins_path() . 'messages/lib/messages.php');
  12. // add page menu items
  13. if (elgg_is_logged_in()) {
  14. elgg_register_menu_item('page', array(
  15. 'name' => 'messages:inbox',
  16. 'text' => elgg_echo('messages:inbox'),
  17. 'href' => "messages/inbox/" . elgg_get_logged_in_user_entity()->username,
  18. 'context' => 'messages',
  19. ));
  20. elgg_register_menu_item('page', array(
  21. 'name' => 'messages:sentmessages',
  22. 'text' => elgg_echo('messages:sentmessages'),
  23. 'href' => "messages/sent/" . elgg_get_logged_in_user_entity()->username,
  24. 'context' => 'messages',
  25. ));
  26. }
  27. elgg_register_event_handler('pagesetup', 'system', 'messages_notifier');
  28. // Extend system CSS with our own styles, which are defined in the messages/css view
  29. elgg_extend_view('css/elgg', 'messages/css');
  30. elgg_extend_view('js/elgg', 'messages/js');
  31. // Register a page handler, so we can have nice URLs
  32. elgg_register_page_handler('messages', 'messages_page_handler');
  33. // Register a URL handler
  34. elgg_register_plugin_hook_handler('entity:url', 'object', 'messages_set_url');
  35. // Extend avatar hover menu
  36. elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'messages_user_hover_menu');
  37. // delete messages sent by a user when user is deleted
  38. elgg_register_event_handler('delete', 'user', 'messages_purge');
  39. // ecml
  40. elgg_register_plugin_hook_handler('get_views', 'ecml', 'messages_ecml_views_hook');
  41. // permission overrides
  42. elgg_register_plugin_hook_handler('permissions_check:metadata', 'object', 'messages_can_edit_metadata');
  43. elgg_register_plugin_hook_handler('permissions_check', 'object', 'messages_can_edit');
  44. elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'messages_can_edit_container');
  45. // Register actions
  46. $action_path = elgg_get_plugins_path() . 'messages/actions/messages';
  47. elgg_register_action("messages/send", "$action_path/send.php");
  48. elgg_register_action("messages/delete", "$action_path/delete.php");
  49. elgg_register_action("messages/process", "$action_path/process.php");
  50. }
  51. /**
  52. * Messages page handler
  53. *
  54. * @param array $page Array of URL components for routing
  55. * @return bool
  56. */
  57. function messages_page_handler($page) {
  58. $current_user = elgg_get_logged_in_user_entity();
  59. if (!$current_user) {
  60. register_error(elgg_echo('noaccess'));
  61. elgg_get_session()->set('last_forward_from', current_page_url());
  62. forward('');
  63. }
  64. elgg_load_library('elgg:messages');
  65. elgg_push_breadcrumb(elgg_echo('messages'), 'messages/inbox/' . $current_user->username);
  66. if (!isset($page[0])) {
  67. $page[0] = 'inbox';
  68. }
  69. // Support the old inbox url /messages/<username>, but only if it matches the logged in user.
  70. // Otherwise having a username like "read" on the system could confuse this function.
  71. if ($current_user->username === $page[0]) {
  72. $page[1] = $page[0];
  73. $page[0] = 'inbox';
  74. }
  75. if (!isset($page[1])) {
  76. $page[1] = $current_user->username;
  77. }
  78. $base_dir = elgg_get_plugins_path() . 'messages/pages/messages';
  79. switch ($page[0]) {
  80. case 'inbox':
  81. set_input('username', $page[1]);
  82. include("$base_dir/inbox.php");
  83. break;
  84. case 'sent':
  85. set_input('username', $page[1]);
  86. include("$base_dir/sent.php");
  87. break;
  88. case 'read':
  89. set_input('guid', $page[1]);
  90. include("$base_dir/read.php");
  91. break;
  92. case 'compose':
  93. case 'add':
  94. include("$base_dir/send.php");
  95. break;
  96. default:
  97. return false;
  98. }
  99. return true;
  100. }
  101. /**
  102. * Display notification of new messages in topbar
  103. */
  104. function messages_notifier() {
  105. if (elgg_is_logged_in()) {
  106. $text = elgg_view_icon("mail");
  107. $tooltip = elgg_echo("messages");
  108. // get unread messages
  109. $num_messages = (int)messages_count_unread();
  110. if ($num_messages != 0) {
  111. $text .= "<span class=\"messages-new\">$num_messages</span>";
  112. $tooltip .= " (" . elgg_echo("messages:unreadcount", array($num_messages)) . ")";
  113. }
  114. elgg_register_menu_item('topbar', array(
  115. 'name' => 'messages',
  116. 'href' => 'messages/inbox/' . elgg_get_logged_in_user_entity()->username,
  117. 'text' => $text,
  118. 'priority' => 600,
  119. 'title' => $tooltip,
  120. ));
  121. }
  122. }
  123. /**
  124. * Override the canEditMetadata function to return true for messages
  125. *
  126. */
  127. function messages_can_edit_metadata($hook_name, $entity_type, $return_value, $parameters) {
  128. global $messagesendflag;
  129. if ($messagesendflag == 1) {
  130. $entity = $parameters['entity'];
  131. if ($entity->getSubtype() == "messages") {
  132. return true;
  133. }
  134. }
  135. return $return_value;
  136. }
  137. /**
  138. * Override the canEdit function to return true for messages within a particular context.
  139. *
  140. */
  141. function messages_can_edit($hook_name, $entity_type, $return_value, $parameters) {
  142. global $messagesendflag;
  143. if ($messagesendflag == 1) {
  144. $entity = $parameters['entity'];
  145. if ($entity->getSubtype() == "messages") {
  146. return true;
  147. }
  148. }
  149. return $return_value;
  150. }
  151. /**
  152. * Prevent messages from generating a notification
  153. */
  154. function messages_notification_msg($hook_name, $entity_type, $return_value, $params) {
  155. if ($params['entity'] instanceof ElggEntity) {
  156. if ($params['entity']->getSubtype() == 'messages') {
  157. return false;
  158. }
  159. }
  160. }
  161. /**
  162. * Override the canEdit function to return true for messages within a particular context.
  163. *
  164. */
  165. function messages_can_edit_container($hook_name, $entity_type, $return_value, $parameters) {
  166. global $messagesendflag;
  167. if ($messagesendflag == 1) {
  168. return true;
  169. }
  170. return $return_value;
  171. }
  172. /**
  173. * Send an internal message
  174. *
  175. * @param string $subject The subject line of the message
  176. * @param string $body The body of the mesage
  177. * @param int $recipient_guid The GUID of the user to send to
  178. * @param int $sender_guid Optionally, the GUID of the user to send from
  179. * @param int $original_msg_guid The GUID of the message to reply from (default: none)
  180. * @param bool $notify Send a notification (default: true)
  181. * @param bool $add_to_sent If true (default), will add a message to the sender's 'sent' tray
  182. * @return bool
  183. */
  184. function messages_send($subject, $body, $recipient_guid, $sender_guid = 0, $original_msg_guid = 0, $notify = true, $add_to_sent = true) {
  185. // @todo remove globals
  186. global $messagesendflag;
  187. $messagesendflag = 1;
  188. // @todo remove globals
  189. global $messages_pm;
  190. if ($notify) {
  191. $messages_pm = 1;
  192. } else {
  193. $messages_pm = 0;
  194. }
  195. // If $sender_guid == 0, set to current user
  196. if ($sender_guid == 0) {
  197. $sender_guid = (int) elgg_get_logged_in_user_guid();
  198. }
  199. // Initialise 2 new ElggObject
  200. $message_to = new ElggObject();
  201. $message_sent = new ElggObject();
  202. $message_to->subtype = "messages";
  203. $message_sent->subtype = "messages";
  204. $message_to->owner_guid = $recipient_guid;
  205. $message_to->container_guid = $recipient_guid;
  206. $message_sent->owner_guid = $sender_guid;
  207. $message_sent->container_guid = $sender_guid;
  208. $message_to->access_id = ACCESS_PUBLIC;
  209. $message_sent->access_id = ACCESS_PUBLIC;
  210. $message_to->title = $subject;
  211. $message_to->description = $body;
  212. $message_sent->title = $subject;
  213. $message_sent->description = $body;
  214. $message_to->toId = $recipient_guid; // the user receiving the message
  215. $message_to->fromId = $sender_guid; // the user receiving the message
  216. $message_to->readYet = 0; // this is a toggle between 0 / 1 (1 = read)
  217. $message_to->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag
  218. $message_to->hiddenTo = 0; // this is used when a user deletes a message in their inbox
  219. $message_sent->toId = $recipient_guid; // the user receiving the message
  220. $message_sent->fromId = $sender_guid; // the user receiving the message
  221. $message_sent->readYet = 0; // this is a toggle between 0 / 1 (1 = read)
  222. $message_sent->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag
  223. $message_sent->hiddenTo = 0; // this is used when a user deletes a message in their inbox
  224. $message_to->msg = 1;
  225. $message_sent->msg = 1;
  226. // Save the copy of the message that goes to the recipient
  227. $success = $message_to->save();
  228. // Save the copy of the message that goes to the sender
  229. if ($add_to_sent) {
  230. $message_sent->save();
  231. }
  232. $message_to->access_id = ACCESS_PRIVATE;
  233. $message_to->save();
  234. if ($add_to_sent) {
  235. $message_sent->access_id = ACCESS_PRIVATE;
  236. $message_sent->save();
  237. }
  238. // if the new message is a reply then create a relationship link between the new message
  239. // and the message it is in reply to
  240. if ($original_msg_guid && $success) {
  241. add_entity_relationship($message_sent->guid, "reply", $original_msg_guid);
  242. }
  243. $message_contents = strip_tags($body);
  244. if (($recipient_guid != elgg_get_logged_in_user_guid()) && $notify) {
  245. $recipient = get_user($recipient_guid);
  246. $sender = get_user($sender_guid);
  247. $subject = elgg_echo('messages:email:subject', array(), $recipient->language);
  248. $body = elgg_echo('messages:email:body', array(
  249. $sender->name,
  250. $message_contents,
  251. elgg_get_site_url() . "messages/inbox/" . $recipient->username,
  252. $sender->name,
  253. elgg_get_site_url() . "messages/compose?send_to=" . $sender_guid
  254. ),
  255. $recipient->language
  256. );
  257. notify_user($recipient_guid, $sender_guid, $subject, $body);
  258. }
  259. $messagesendflag = 0;
  260. return $success;
  261. }
  262. /**
  263. * Message URL override
  264. *
  265. * @param string $hook
  266. * @param string $type
  267. * @param string $url
  268. * @param array $params
  269. * @return string
  270. */
  271. function messages_set_url($hook, $type, $url, $params) {
  272. $entity = $params['entity'];
  273. if (elgg_instanceof($entity, 'object', 'messages')) {
  274. return 'messages/read/' . $entity->getGUID();
  275. }
  276. }
  277. function count_unread_messages() {
  278. elgg_deprecated_notice('Your theme is using count_unread_messages which has been deprecated for messages_count_unread()', 1.8);
  279. return messages_count_unread();
  280. }
  281. /**
  282. * Returns the unread messages in a user's inbox
  283. *
  284. * @param int $user_guid GUID of user whose inbox we're counting (0 for logged in user)
  285. * @param int $limit Number of unread messages to return (default from settings)
  286. * @param int $offset Start at a defined offset (for listings)
  287. * @param bool $count Switch between entities array or count mode
  288. *
  289. * @return array, int (if $count = true)
  290. * @since 1.9
  291. */
  292. function messages_get_unread($user_guid = 0, $limit = null, $offset = 0, $count = false) {
  293. if (!$user_guid) {
  294. $user_guid = elgg_get_logged_in_user_guid();
  295. }
  296. $db_prefix = elgg_get_config('dbprefix');
  297. // denormalize the md to speed things up.
  298. // seriously, 10 joins if you don't.
  299. $strings = array('toId', $user_guid, 'readYet', 0, 'msg', 1);
  300. $map = array();
  301. foreach ($strings as $string) {
  302. $id = elgg_get_metastring_id($string);
  303. $map[$string] = $id;
  304. }
  305. if ($limit === null) {
  306. $limit = elgg_get_config('default_limit');
  307. }
  308. $options = array(
  309. // original options before denormalizing
  310. // 'metadata_name_value_pairs' => array(
  311. // 'toId' => elgg_get_logged_in_user_guid(),
  312. // 'readYet' => 0,
  313. // 'msg' => 1
  314. // ),
  315. 'joins' => array(
  316. "JOIN {$db_prefix}metadata msg_toId on e.guid = msg_toId.entity_guid",
  317. "JOIN {$db_prefix}metadata msg_readYet on e.guid = msg_readYet.entity_guid",
  318. "JOIN {$db_prefix}metadata msg_msg on e.guid = msg_msg.entity_guid",
  319. ),
  320. 'wheres' => array(
  321. "msg_toId.name_id='{$map['toId']}' AND msg_toId.value_id='{$map[$user_guid]}'",
  322. "msg_readYet.name_id='{$map['readYet']}' AND msg_readYet.value_id='{$map[0]}'",
  323. "msg_msg.name_id='{$map['msg']}' AND msg_msg.value_id='{$map[1]}'",
  324. ),
  325. 'owner_guid' => $user_guid,
  326. 'limit' => $limit,
  327. 'offset' => $offset,
  328. 'count' => $count,
  329. 'distinct' => false,
  330. );
  331. return elgg_get_entities_from_metadata($options);
  332. }
  333. /**
  334. * Count the unread messages in a user's inbox
  335. *
  336. * @param int $user_guid GUID of user whose inbox we're counting (0 for logged in user)
  337. *
  338. * @return int
  339. */
  340. function messages_count_unread($user_guid = 0) {
  341. return messages_get_unread($user_guid, 10, 0, true);
  342. }
  343. /**
  344. * Add to the user hover menu
  345. */
  346. function messages_user_hover_menu($hook, $type, $return, $params) {
  347. $user = $params['entity'];
  348. if (elgg_is_logged_in() && elgg_get_logged_in_user_guid() != $user->guid) {
  349. $url = "messages/compose?send_to={$user->guid}";
  350. $item = new ElggMenuItem('send', elgg_echo('messages:sendmessage'), $url);
  351. $item->setSection('action');
  352. $return[] = $item;
  353. }
  354. return $return;
  355. }
  356. /**
  357. * Delete messages from a user who is being deleted
  358. *
  359. * @param string $event Event name
  360. * @param string $type Event type
  361. * @param ElggUser $user User being deleted
  362. */
  363. function messages_purge($event, $type, $user) {
  364. if (!$user->getGUID()) {
  365. return;
  366. }
  367. // make sure we delete them all
  368. $entity_disable_override = access_get_show_hidden_status();
  369. access_show_hidden_entities(true);
  370. $ia = elgg_set_ignore_access(true);
  371. $options = array(
  372. 'type' => 'object',
  373. 'subtype' => 'messages',
  374. 'metadata_name' => 'fromId',
  375. 'metadata_value' => $user->getGUID(),
  376. 'limit' => 0,
  377. );
  378. $batch = new ElggBatch('elgg_get_entities_from_metadata', $options);
  379. foreach ($batch as $e) {
  380. $e->delete();
  381. }
  382. elgg_set_ignore_access($ia);
  383. access_show_hidden_entities($entity_disable_override);
  384. }
  385. /**
  386. * Register messages with ECML.
  387. *
  388. * @param string $hook
  389. * @param string $entity_type
  390. * @param string $return_value
  391. * @param array $params
  392. *
  393. * @return array
  394. */
  395. function messages_ecml_views_hook($hook, $entity_type, $return_value, $params) {
  396. $return_value['messages/messages'] = elgg_echo('messages');
  397. return $return_value;
  398. }