1<?php 2/** 3* Elgg internal messages plugin 4* This plugin lets users send messages to each other. 5*/ 6 7/** 8 * Messages init 9 * 10 * @return void 11 */ 12function messages_init() { 13 14 // add page menu items 15 $user = elgg_get_logged_in_user_entity(); 16 if (!empty($user)) { 17 elgg_register_menu_item('page', [ 18 'name' => 'messages:inbox', 19 'text' => elgg_echo('messages:inbox'), 20 'href' => elgg_generate_url('collection:object:messages:owner', [ 21 'username' => $user->username, 22 ]), 23 'context' => 'messages', 24 ]); 25 26 elgg_register_menu_item('page', [ 27 'name' => 'messages:sentmessages', 28 'text' => elgg_echo('messages:sentmessages'), 29 'href' => elgg_generate_url('collection:object:messages:sent', [ 30 'username' => $user->username, 31 ]), 32 'context' => 'messages', 33 ]); 34 } 35 36 // Extend system CSS with our own styles, which are defined in the messages/css view 37 elgg_extend_view('elgg.css', 'messages/css'); 38 elgg_extend_view('elgg.js', 'messages/js'); 39 40 // Extend avatar hover menu 41 elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'messages_user_hover_menu'); 42 elgg_register_plugin_hook_handler('register', 'menu:title', 'messages_user_hover_menu'); 43 44 // delete messages sent by a user when user is deleted 45 elgg_register_event_handler('delete', 'user', 'messages_purge'); 46 47 // ecml 48 elgg_register_plugin_hook_handler('get_views', 'ecml', 'messages_ecml_views_hook'); 49 50 // permission overrides 51 elgg_register_plugin_hook_handler('permissions_check', 'object', 'messages_can_edit'); 52 elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'messages_can_edit_container'); 53 54 // Topbar menu. We assume this menu will render *after* a message is rendered. If a refactor/plugin 55 // causes it to render first, the unread count notification will not update until the next page. 56 elgg_register_plugin_hook_handler('register', 'menu:topbar', 'messages_register_topbar'); 57} 58 59/** 60 * Add inbox link to topbar 61 * 62 * @param \Elgg\Hook $hook "register", "menu:topbar" 63 * 64 * @return void|ElggMenuItem[] 65 */ 66function messages_register_topbar(\Elgg\Hook $hook) { 67 if (!elgg_is_logged_in()) { 68 return; 69 } 70 71 $user = elgg_get_logged_in_user_entity(); 72 73 $text = elgg_echo('messages'); 74 $title = $text; 75 76 $num_messages = (int) messages_count_unread(); 77 if ($num_messages) { 78 $title .= " (" . elgg_echo("messages:unreadcount", [$num_messages]) . ")"; 79 } 80 81 $items = $hook->getValue(); 82 $items[] = ElggMenuItem::factory([ 83 'name' => 'messages', 84 'href' => elgg_generate_url('collection:object:messages:owner', [ 85 'username' => $user->username, 86 ]), 87 'text' => $text, 88 'priority' => 600, 89 'title' => $title, 90 'icon' => 'mail', 91 'badge' => $num_messages ? $num_messages : null, 92 ]); 93 94 return $items; 95} 96 97/** 98 * Override the canEdit function to return true for messages within a particular context 99 * 100 * @param \Elgg\Hook $hook 'permissions_check', 'object' 101 * 102 * @return void|true 103 */ 104function messages_can_edit(\Elgg\Hook $hook) { 105 106 global $messagesendflag; 107 if ($messagesendflag !== 1) { 108 return; 109 } 110 111 $entity = $hook->getEntityParam(); 112 if ($entity instanceof ElggObject && $entity->getSubtype() == 'messages') { 113 return true; 114 } 115} 116 117/** 118 * Override the canEdit function to return true for messages within a particular context 119 * 120 * @param \Elgg\Hook $hook 'container_permissions_check', 'object' 121 * 122 * @return void|true 123 */ 124function messages_can_edit_container(\Elgg\Hook $hook) { 125 126 global $messagesendflag; 127 if ($messagesendflag == 1) { 128 return true; 129 } 130} 131 132/** 133 * Send an internal message 134 * 135 * @param string $subject The subject line of the message 136 * @param string $body The body of the mesage 137 * @param int $recipient_guid The GUID of the user to send to 138 * @param int $sender_guid Optionally, the GUID of the user to send from 139 * @param int $original_msg_guid The GUID of the message to reply from (default: none) 140 * @param bool $notify Send a notification (default: true) 141 * @param bool $add_to_sent If true (default), will add a message to the sender's 'sent' tray 142 * 143 * @return false|int 144 */ 145function messages_send($subject, $body, $recipient_guid, $sender_guid = 0, $original_msg_guid = 0, $notify = true, $add_to_sent = true) { 146 147 // @todo remove globals 148 global $messagesendflag; 149 $messagesendflag = 1; 150 151 // @todo remove globals 152 global $messages_pm; 153 if ($notify) { 154 $messages_pm = 1; 155 } else { 156 $messages_pm = 0; 157 } 158 159 // If $sender_guid == 0, set to current user 160 if ($sender_guid == 0) { 161 $sender_guid = (int) elgg_get_logged_in_user_guid(); 162 } 163 164 $message_to = new ElggMessage(); 165 $message_sent = new ElggMessage(); 166 167 $message_to->owner_guid = $recipient_guid; 168 $message_to->container_guid = $recipient_guid; 169 $message_sent->owner_guid = $sender_guid; 170 $message_sent->container_guid = $sender_guid; 171 172 $message_to->access_id = ACCESS_PUBLIC; 173 $message_sent->access_id = ACCESS_PUBLIC; 174 175 $message_to->title = $subject; 176 $message_to->description = $body; 177 178 $message_sent->title = $subject; 179 $message_sent->description = $body; 180 181 $message_to->toId = $recipient_guid; // the user receiving the message 182 $message_to->fromId = $sender_guid; // the user receiving the message 183 $message_to->readYet = 0; // this is a toggle between 0 / 1 (1 = read) 184 $message_to->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag 185 $message_to->hiddenTo = 0; // this is used when a user deletes a message in their inbox 186 187 $message_sent->toId = $recipient_guid; // the user receiving the message 188 $message_sent->fromId = $sender_guid; // the user receiving the message 189 $message_sent->readYet = 0; // this is a toggle between 0 / 1 (1 = read) 190 $message_sent->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag 191 $message_sent->hiddenTo = 0; // this is used when a user deletes a message in their inbox 192 193 // Save the copy of the message that goes to the recipient 194 $success = $message_to->save(); 195 196 // Save the copy of the message that goes to the sender 197 if ($add_to_sent) { 198 $message_sent->save(); 199 } 200 201 $message_to->access_id = ACCESS_PRIVATE; 202 $message_to->save(); 203 204 if ($add_to_sent) { 205 $message_sent->access_id = ACCESS_PRIVATE; 206 $message_sent->save(); 207 } 208 209 // if the new message is a reply then create a relationship link between the new message 210 // and the message it is in reply to 211 if ($original_msg_guid && $success) { 212 add_entity_relationship($message_sent->guid, "reply", $original_msg_guid); 213 } 214 215 if (($recipient_guid != elgg_get_logged_in_user_guid()) && $notify) { 216 $message_contents = $body; 217 $recipient = get_user($recipient_guid); 218 $sender = get_user($sender_guid); 219 220 $subject = elgg_echo('messages:email:subject', [], $recipient->language); 221 $body = elgg_echo('messages:email:body', [ 222 $sender->getDisplayName(), 223 $message_contents, 224 elgg_generate_url('collection:object:messages:owner', [ 225 'username' => $recipient->username, 226 ]), 227 $sender->getDisplayName(), 228 elgg_generate_url('add:object:messages', [ 229 'send_to' => $sender_guid, 230 ]), 231 ], 232 $recipient->language 233 ); 234 235 $params = [ 236 'object' => $message_to, 237 'action' => 'send', 238 'url' => $message_to->getURL(), 239 ]; 240 notify_user($recipient_guid, $sender_guid, $subject, $body, $params); 241 } 242 243 $messagesendflag = 0; 244 return $success; 245} 246 247/** 248 * Message URL override 249 * 250 * @param string $hook 'entity:url' 251 * @param string $type 'object' 252 * @param string $url current return value 253 * @param array $params supplied params 254 * 255 * @return void|string|false 256 * @deprecated 3.0 use ElggEntity::getURL() 257 */ 258function messages_set_url($hook, $type, $url, $params) { 259 260 $entity = elgg_extract('entity', $params); 261 if (!$entity instanceof ElggObject || $entity->getSubtype() !== 'messages') { 262 return; 263 } 264 265 elgg_deprecated_notice(__METHOD__ . ' is deprecated please use ElggEntity::getURL()', '3.0'); 266 267 return elgg_generate_entity_url($entity); 268} 269 270/** 271 * Returns the unread messages in a user's inbox 272 * 273 * @param int $user_guid GUID of user whose inbox we're counting (0 for logged in user) 274 * @param int $limit Number of unread messages to return (default from settings) 275 * @param int $offset Start at a defined offset (for listings) 276 * @param bool $count Switch between entities array or count mode 277 * 278 * @return ElggMessage[]|int|false 279 * @since 1.9 280 */ 281function messages_get_unread($user_guid = 0, $limit = null, $offset = 0, $count = false) { 282 if (!$user_guid) { 283 $user_guid = elgg_get_logged_in_user_guid(); 284 } 285 286 return elgg_get_entities([ 287 'type' => 'object', 288 'subtype' => 'messages', 289 'metadata_name_value_pairs' => [ 290 'toId' => (int) $user_guid, 291 'readYet' => 0, 292 ], 293 'owner_guid' => (int) $user_guid, 294 'limit' => $limit ? : elgg_get_config('default_limit'), 295 'offset' => $offset, 296 'count' => $count, 297 'distinct' => false, 298 ]); 299} 300 301/** 302 * Count the unread messages in a user's inbox 303 * 304 * @param int $user_guid GUID of user whose inbox we're counting (0 for logged in user) 305 * 306 * @return int 307 */ 308function messages_count_unread($user_guid = 0) { 309 return (int) messages_get_unread($user_guid, 10, 0, true); 310} 311 312/** 313 * Prepare the compose form variables 314 * 315 * @param int $recipient_guid new message recipient 316 * 317 * @return array 318 */ 319function messages_prepare_form_vars($recipient_guid = 0) { 320 321 $recipients = []; 322 $recipient = get_user($recipient_guid); 323 if (!empty($recipient)) { 324 $recipients[] = $recipient->getGUID(); 325 } 326 327 // input names => defaults 328 $values = [ 329 'subject' => elgg_get_sticky_value('messages', 'subject', ''), 330 'body' => elgg_get_sticky_value('messages', 'body', ''), 331 'recipients' => elgg_get_sticky_value('messages', 'recipients', $recipients), 332 ]; 333 334 elgg_clear_sticky_form('messages'); 335 336 return $values; 337} 338 339/** 340 * Add to the user hover menu 341 * 342 * @param \Elgg\Hook $hook 'register', 'menu:user_hover' or 'menu:title' 343 * 344 * @return void|ElggMenuItem[] 345 */ 346function messages_user_hover_menu(\Elgg\Hook $hook) { 347 348 $user = $hook->getEntityParam(); 349 if (!elgg_is_logged_in() || !$user instanceof ElggUser) { 350 return; 351 } 352 353 if (elgg_get_logged_in_user_guid() === $user->guid) { 354 return; 355 } 356 357 $menu_options = [ 358 'name' => 'send', 359 'text' => elgg_echo('messages:sendmessage'), 360 'icon' => 'mail', 361 'href' => elgg_generate_url('add:object:messages', [ 362 'send_to' => $user->guid, 363 ]), 364 ]; 365 366 if ($hook->getType() == 'menu:user_hover') { 367 $menu_options['section'] = 'action'; 368 } 369 370 if ($hook->getType() == 'menu:title') { 371 $menu_options['class'] = ['elgg-button', 'elgg-button-action']; 372 } 373 374 $return = $hook->getValue(); 375 $return[] = ElggMenuItem::factory($menu_options); 376 377 return $return; 378} 379 380/** 381 * Delete messages from a user who is being deleted 382 * 383 * @param \Elgg\Event $event 'delete', 'user' 384 * 385 * @return void 386 */ 387function messages_purge(\Elgg\Event $event) { 388 $user = $event->getObject(); 389 if (!$user->guid) { 390 return; 391 } 392 393 // make sure we delete them all 394 elgg_call(ELGG_IGNORE_ACCESS | ELGG_SHOW_DISABLED_ENTITIES, function() use ($user) { 395 $batch = new ElggBatch('elgg_get_entities', [ 396 'type' => 'object', 397 'subtype' => 'messages', 398 'metadata_name_value_pairs' => [ 399 'fromId' => $user->guid, 400 ], 401 'limit' => false, 402 ]); 403 $batch->setIncrementOffset(false); 404 foreach ($batch as $e) { 405 $e->delete(); 406 } 407 }); 408} 409 410/** 411 * Register messages with ECML. 412 * 413 * @param \Elgg\Hook $hook 'get_views', 'ecml' 414 * 415 * @return array 416 */ 417function messages_ecml_views_hook(\Elgg\Hook $hook) { 418 $return_value = $hook->getValue(); 419 $return_value['messages/messages'] = elgg_echo('messages'); 420 return $return_value; 421} 422 423return function() { 424 elgg_register_event_handler('init', 'system', 'messages_init'); 425}; 426