Passed
Push — master ( c0a3a7...3b84a4 )
by Jeroen
58:51
created

mod/messages/start.php (12 issues)

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
 */
12
function messages_init() {
13
14
	// add page menu items
15 31
	if (elgg_is_logged_in()) {
16
		elgg_register_menu_item('page', [
17
			'name' => 'messages:inbox',
18
			'text' => elgg_echo('messages:inbox'),
19
			'href' => "messages/inbox/" . elgg_get_logged_in_user_entity()->username,
20
			'context' => 'messages',
21
		]);
22
		
23
		elgg_register_menu_item('page', [
24
			'name' => 'messages:sentmessages',
25
			'text' => elgg_echo('messages:sentmessages'),
26
			'href' => "messages/sent/" . elgg_get_logged_in_user_entity()->username,
27
			'context' => 'messages',
28
		]);
29
	}
30
31
	// Extend system CSS with our own styles, which are defined in the messages/css view
32 31
	elgg_extend_view('elgg.css', 'messages/css');
33 31
	elgg_extend_view('elgg.js', 'messages/js');
34
	
35
	// Register a page handler, so we can have nice URLs
36 31
	elgg_register_page_handler('messages', 'messages_page_handler');
37
38
	// Register a URL handler
39 31
	elgg_register_plugin_hook_handler('entity:url', 'object', 'messages_set_url');
40
41
	// Extend avatar hover menu
42 31
	elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'messages_user_hover_menu');
43
44
	// delete messages sent by a user when user is deleted
45 31
	elgg_register_event_handler('delete', 'user', 'messages_purge');
46
47
	// ecml
48 31
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'messages_ecml_views_hook');
49
50
	// permission overrides
51 31
	elgg_register_plugin_hook_handler('permissions_check:metadata', 'object', 'messages_can_edit_metadata');
52 31
	elgg_register_plugin_hook_handler('permissions_check', 'object', 'messages_can_edit');
53 31
	elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'messages_can_edit_container');
54
55
	// Topbar menu. We assume this menu will render *after* a message is rendered. If a refactor/plugin
56
	// causes it to render first, the unread count notification will not update until the next page.
57 31
	elgg_register_plugin_hook_handler('register', 'menu:topbar', 'messages_register_topbar');
58 31
}
59
60
/**
61
 * Messages page handler
62
 *
63
 * @param array $page Array of URL components for routing
64
 *
65
 * @return bool
66
 */
67
function messages_page_handler($page) {
68
69
	elgg_gatekeeper();
70
	$current_user = elgg_get_logged_in_user_entity();
71
72
	elgg_push_breadcrumb(elgg_echo('messages'), 'messages/inbox/' . $current_user->username);
73
74
	if (!isset($page[0])) {
75
		$page[0] = 'inbox';
76
	}
77
78
	// Support the old inbox url /messages/<username>, but only if it matches the logged in user.
79
	// Otherwise having a username like "read" on the system could confuse this function.
80
	if ($current_user->username === $page[0]) {
81
		$page[1] = $page[0];
82
		$page[0] = 'inbox';
83
	}
84
85
	if (!isset($page[1])) {
86
		$page[1] = $current_user->username;
87
	}
88
89
	switch ($page[0]) {
90
		case 'inbox':
91
			echo elgg_view_resource('messages/inbox', [
92
				'username' => $page[1],
93
			]);
94
			break;
95
		case 'sent':
96
			echo elgg_view_resource('messages/sent', [
97
				'username' => $page[1],
98
			]);
99
			break;
100
		case 'read':
101
			echo elgg_view_resource('messages/read', [
102
				'guid' => $page[1],
103
			]);
104
			break;
105
		case 'compose':
106
		case 'add':
107
			echo elgg_view_resource('messages/send');
108
			break;
109
		default:
110
			return false;
111
	}
112
	return true;
113
}
114
115
/**
116
 * Add inbox link to topbar
117
 *
118
 * @param string         $hook   "register"
119
 * @param string         $type   "menu:topbar"
120
 * @param ElggMenuItem[] $items  Menu items
121
 * @param array          $params Hook params
122
 *
123
 * @return void|ElggMenuItem[]
124
 */
125
function messages_register_topbar($hook, $type, $items, $params) {
126 1
	if (!elgg_is_logged_in()) {
127 1
		return;
128
	}
129
130
	$user = elgg_get_logged_in_user_entity();
131
132
	$text = elgg_echo('messages');
133
	$title = $text;
134
135
	$num_messages = (int) messages_count_unread();
136
	if ($num_messages) {
137
		$title .= " (" . elgg_echo("messages:unreadcount", [$num_messages]) . ")";
138
	}
139
140
	$items[] = ElggMenuItem::factory([
141
		'name' => 'messages',
142
		'href' => "messages/inbox/$user->username",
143
		'text' => $text,
144
		'priority' => 600,
145
		'title' => $title,
146
		'icon' => 'mail',
147
		'badge' => $num_messages ? $num_messages : null,
148
	]);
149
150
	return $items;
151
}
152
153
/**
154
 * Override the canEditMetadata function to return true for messages
155
 *
156
 * @param string $hook         'permissions_check:metadata'
157
 * @param string $type         'object'
158
 * @param bool   $return_value current return value
159
 * @param array  $parameters   supplied params
160
 *
161
 * @return void|true
162
 */
163
function messages_can_edit_metadata($hook, $type, $return_value, $parameters) {
3 ignored issues
show
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

163
function messages_can_edit_metadata(/** @scrutinizer ignore-unused */ $hook, $type, $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $return_value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

163
function messages_can_edit_metadata($hook, $type, /** @scrutinizer ignore-unused */ $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

163
function messages_can_edit_metadata($hook, /** @scrutinizer ignore-unused */ $type, $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
164
165 14
	global $messagesendflag;
166
167 14
	if ($messagesendflag !== 1) {
168 14
		return;
169
	}
170
	
171
	$entity = elgg_extract('entity', $parameters);
172
	if ($entity instanceof ElggObject && $entity->getSubtype() == 'messages') {
173
		return true;
174
	}
175
}
176
177
/**
178
 * Override the canEdit function to return true for messages within a particular context
179
 *
180
 * @param string $hook         'permissions_check'
181
 * @param string $type         'object'
182
 * @param bool   $return_value current return value
183
 * @param array  $parameters   supplied params
184
 *
185
 * @return void|true
186
 */
187
function messages_can_edit($hook, $type, $return_value, $parameters) {
3 ignored issues
show
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

187
function messages_can_edit(/** @scrutinizer ignore-unused */ $hook, $type, $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

187
function messages_can_edit($hook, /** @scrutinizer ignore-unused */ $type, $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $return_value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

187
function messages_can_edit($hook, $type, /** @scrutinizer ignore-unused */ $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
188
189 113
	global $messagesendflag;
190
	
191 113
	if ($messagesendflag !== 1) {
192 111
		return;
193
	}
194
	
195 2
	$entity = elgg_extract('entity', $parameters);
196 2
	if ($entity instanceof ElggObject && $entity->getSubtype() == 'messages') {
197 2
		return true;
198
	}
199
}
200
201
/**
202
 * Override the canEdit function to return true for messages within a particular context
203
 *
204
 * @param string $hook         'container_permissions_check'
205
 * @param string $type         'object'
206
 * @param bool   $return_value current return value
207
 * @param array  $parameters   supplied params
208
 *
209
 * @return void|true
210
 */
211
function messages_can_edit_container($hook, $type, $return_value, $parameters) {
4 ignored issues
show
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

211
function messages_can_edit_container($hook, /** @scrutinizer ignore-unused */ $type, $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $return_value is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

211
function messages_can_edit_container($hook, $type, /** @scrutinizer ignore-unused */ $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $hook is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

211
function messages_can_edit_container(/** @scrutinizer ignore-unused */ $hook, $type, $return_value, $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
The parameter $parameters is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

211
function messages_can_edit_container($hook, $type, $return_value, /** @scrutinizer ignore-unused */ $parameters) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
212
213 8
	global $messagesendflag;
214
215 8
	if ($messagesendflag == 1) {
216 2
		return true;
217
	}
218 6
}
219
220
/**
221
 * Send an internal message
222
 *
223
 * @param string $subject           The subject line of the message
224
 * @param string $body              The body of the mesage
225
 * @param int    $recipient_guid    The GUID of the user to send to
226
 * @param int    $sender_guid       Optionally, the GUID of the user to send from
227
 * @param int    $original_msg_guid The GUID of the message to reply from (default: none)
228
 * @param bool   $notify            Send a notification (default: true)
229
 * @param bool   $add_to_sent       If true (default), will add a message to the sender's 'sent' tray
230
 *
231
 * @return false|int
232
 */
233
function messages_send($subject, $body, $recipient_guid, $sender_guid = 0, $original_msg_guid = 0, $notify = true, $add_to_sent = true) {
234
235
	// @todo remove globals
236 2
	global $messagesendflag;
237 2
	$messagesendflag = 1;
238
239
	// @todo remove globals
240 2
	global $messages_pm;
241 2
	if ($notify) {
242 2
		$messages_pm = 1;
243
	} else {
244
		$messages_pm = 0;
245
	}
246
247
	// If $sender_guid == 0, set to current user
248 2
	if ($sender_guid == 0) {
249 1
		$sender_guid = (int) elgg_get_logged_in_user_guid();
250
	}
251
252 2
	$message_to = new ElggMessage();
253 2
	$message_sent = new ElggMessage();
254
255 2
	$message_to->owner_guid = $recipient_guid;
256 2
	$message_to->container_guid = $recipient_guid;
257 2
	$message_sent->owner_guid = $sender_guid;
258 2
	$message_sent->container_guid = $sender_guid;
259
260 2
	$message_to->access_id = ACCESS_PUBLIC;
261 2
	$message_sent->access_id = ACCESS_PUBLIC;
262
263 2
	$message_to->title = $subject;
264 2
	$message_to->description = $body;
265
266 2
	$message_sent->title = $subject;
267 2
	$message_sent->description = $body;
268
269 2
	$message_to->toId = $recipient_guid; // the user receiving the message
270 2
	$message_to->fromId = $sender_guid; // the user receiving the message
271 2
	$message_to->readYet = 0; // this is a toggle between 0 / 1 (1 = read)
272 2
	$message_to->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag
273 2
	$message_to->hiddenTo = 0; // this is used when a user deletes a message in their inbox
274
275 2
	$message_sent->toId = $recipient_guid; // the user receiving the message
276 2
	$message_sent->fromId = $sender_guid; // the user receiving the message
277 2
	$message_sent->readYet = 0; // this is a toggle between 0 / 1 (1 = read)
278 2
	$message_sent->hiddenFrom = 0; // this is used when a user deletes a message in their sentbox, it is a flag
279 2
	$message_sent->hiddenTo = 0; // this is used when a user deletes a message in their inbox
280
281
	// Save the copy of the message that goes to the recipient
282 2
	$success = $message_to->save();
283
284
	// Save the copy of the message that goes to the sender
285 2
	if ($add_to_sent) {
286 2
		$message_sent->save();
287
	}
288
289 2
	$message_to->access_id = ACCESS_PRIVATE;
290 2
	$message_to->save();
291
292 2
	if ($add_to_sent) {
293 2
		$message_sent->access_id = ACCESS_PRIVATE;
294 2
		$message_sent->save();
295
	}
296
297
	// if the new message is a reply then create a relationship link between the new message
298
	// and the message it is in reply to
299 2
	if ($original_msg_guid && $success) {
300
		add_entity_relationship($message_sent->guid, "reply", $original_msg_guid);
301
	}
302
303 2
	$message_contents = strip_tags($body);
304 2
	if (($recipient_guid != elgg_get_logged_in_user_guid()) && $notify) {
305 2
		$recipient = get_user($recipient_guid);
306 2
		$sender = get_user($sender_guid);
307
		
308 2
		$subject = elgg_echo('messages:email:subject', [], $recipient->language);
309 2
		$body = elgg_echo('messages:email:body', [
310 2
				$sender->name,
311 2
				$message_contents,
312 2
				elgg_get_site_url() . "messages/inbox/" . $recipient->username,
313 2
				$sender->name,
314 2
				elgg_get_site_url() . "messages/compose?send_to=" . $sender_guid
315
			],
316 2
			$recipient->language
317
		);
318
319
		$params = [
320 2
			'object' => $message_to,
321 2
			'action' => 'send',
322 2
			'url' => $message_to->getURL(),
323
		];
324 2
		notify_user($recipient_guid, $sender_guid, $subject, $body, $params);
325
	}
326
327 2
	$messagesendflag = 0;
328 2
	return $success;
329
}
330
331
/**
332
 * Message URL override
333
 *
334
 * @param string $hook   'entity:url'
335
 * @param string $type   'object'
336
 * @param string $url    current return value
337
 * @param array  $params supplied params
338
 *
339
 * @return void|string
340
 */
341
function messages_set_url($hook, $type, $url, $params) {
342
	
343 3
	$entity = elgg_extract('entity', $params);
344 3
	if (!$entity instanceof ElggObject || $entity->getSubtype() !== 'messages') {
345 1
		return;
346
	}
347
	
348 2
	return "messages/read/{$entity->getGUID()}";
349
}
350
351
/**
352
 * Returns the unread messages in a user's inbox
353
 *
354
 * @param int  $user_guid GUID of user whose inbox we're counting (0 for logged in user)
355
 * @param int  $limit     Number of unread messages to return (default from settings)
356
 * @param int  $offset    Start at a defined offset (for listings)
357
 * @param bool $count     Switch between entities array or count mode
358
 *
359
 * @return ElggObject[]|int
360
 * @since 1.9
361
 */
362
function messages_get_unread($user_guid = 0, $limit = null, $offset = 0, $count = false) {
363 1
	if (!$user_guid) {
364
		$user_guid = elgg_get_logged_in_user_guid();
365
	}
366
367 1
	return elgg_get_entities([
0 ignored issues
show
Bug Best Practice introduced by
The expression return elgg_get_entities..., 'distinct' => false)) could also return false which is incompatible with the documented return type ElggObject[]|integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
368 1
		'type' => 'object',
369 1
		'subtype' => 'messages',
370
		'metadata_name_value_pairs' => [
371 1
			'toId' => (int) $user_guid,
372 1
			'readYet' => 0,
373
		],
374 1
		'owner_guid' => (int) $user_guid,
375 1
		'limit' => $limit ? : elgg_get_config('default_limit'),
376 1
		'offset' => $offset,
377 1
		'count' => $count,
378
		'distinct' => false,
379
	]);
380
}
381
382
/**
383
 * Count the unread messages in a user's inbox
384
 *
385
 * @param int $user_guid GUID of user whose inbox we're counting (0 for logged in user)
386
 *
387
 * @return int
388
 */
389
function messages_count_unread($user_guid = 0) {
390 1
	return messages_get_unread($user_guid, 10, 0, true);
391
}
392
393
/**
394
 * Prepare the compose form variables
395
 *
396
 * @param int $recipient_guid new message recipient
397
 *
398
 * @return array
399
 */
400
function messages_prepare_form_vars($recipient_guid = 0) {
401
402
	$recipients = [];
403
	$recipient = get_user($recipient_guid);
404
	if (!empty($recipient)) {
405
		$recipients[] = $recipient->getGUID();
406
	}
407
408
	// input names => defaults
409
	$values = [
410
		'subject' => elgg_get_sticky_value('messages', 'subject', ''),
411
		'body' => elgg_get_sticky_value('messages', 'body', ''),
412
		'recipients' => elgg_get_sticky_value('messages', 'recipients', $recipients),
413
	];
414
415
	elgg_clear_sticky_form('messages');
416
417
	return $values;
418
}
419
420
/**
421
 * Add to the user hover menu
422
 *
423
 * @param string         $hook   'register'
424
 * @param string         $type   'menu:user_hover'
425
 * @param ElggMenuItem[] $return current return value
426
 * @param array          $params supplied params
427
 *
428
 * @return void|ElggMenuItem[]
429
 */
430
function messages_user_hover_menu($hook, $type, $return, $params) {
431
	
432 1
	$user = elgg_extract('entity', $params);
433 1
	if (!elgg_is_logged_in() || !$user instanceof ElggUser) {
434 1
		return;
435
	}
436
	
437
	if (elgg_get_logged_in_user_guid() === $user->guid) {
438
		return;
439
	}
440
	
441
	$return[] = ElggMenuItem::factory([
442
		'name' => 'send',
443
		'text' => elgg_echo('messages:sendmessage'),
444
		'icon' => 'mail',
445
		'href' => "messages/compose?send_to={$user->guid}",
446
		'section' => 'action',
447
	]);
448
449
	return $return;
450
}
451
452
/**
453
 * Delete messages from a user who is being deleted
454
 *
455
 * @param string   $event Event name
456
 * @param string   $type  Event type
457
 * @param ElggUser $user  User being deleted
458
 *
459
 * @return void
460
 */
461
function messages_purge($event, $type, $user) {
462
463 70
	if (!$user->getGUID()) {
464
		return;
465
	}
466
467
	// make sure we delete them all
468 70
	$entity_disable_override = access_show_hidden_entities(true);
469 70
	$ia = elgg_set_ignore_access(true);
470
471
	$options = [
472 70
		'type' => 'object',
473 70
		'subtype' => 'messages',
474
		'metadata_name_value_pairs' => [
475 70
			'fromId' => $user->guid,
476
		],
477
		'limit' => false,
478
	];
479 70
	$batch = new ElggBatch('elgg_get_entities_from_metadata', $options);
480 70
	$batch->setIncrementOffset(false);
481 70
	foreach ($batch as $e) {
482
		$e->delete();
483
	}
484
485 70
	elgg_set_ignore_access($ia);
486 70
	access_show_hidden_entities($entity_disable_override);
487 70
}
488
489
/**
490
 * Register messages with ECML.
491
 *
492
 * @param string $hook         'get_views'
493
 * @param string $type         'ecml'
494
 * @param string $return_value current return value
495
 * @param array  $params       supplied params
496
 *
497
 * @return array
498
 */
499
function messages_ecml_views_hook($hook, $type, $return_value, $params) {
1 ignored issue
show
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

499
function messages_ecml_views_hook($hook, /** @scrutinizer ignore-unused */ $type, $return_value, $params) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
500
	$return_value['messages/messages'] = elgg_echo('messages');
501
502
	return $return_value;
503
}
504
505
return function() {
506 18
	elgg_register_event_handler('init', 'system', 'messages_init');
507
};
508