Issues (2473)

Branch: master

Security Analysis    no vulnerabilities found

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

mod/groups/start.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

Code
1
<?php
2
/**
3
 * Elgg groups plugin
4
 *
5
 * @package ElggGroups
6
 */
7
8
elgg_register_event_handler('init', 'system', 'groups_init');
9
10
// Ensure this runs after other plugins
11
elgg_register_event_handler('init', 'system', 'groups_fields_setup', 10000);
12
13
/**
14
 * Initialize the groups plugin.
15
 */
16
function groups_init() {
17
18
	elgg_register_library('elgg:groups', elgg_get_plugins_path() . 'groups/lib/groups.php');
19
20
	// register group entities for search
21
	elgg_register_entity_type('group', '');
22
23
	// Set up the menu
24
	$item = new ElggMenuItem('groups', elgg_echo('groups'), 'groups/featured');
25
	elgg_register_menu_item('site', $item);
26
27
	// Register a page handler, so we can have nice URLs
28
	elgg_register_page_handler('groups', 'groups_page_handler');
29
30
	// Register URL handlers for groups
31
	elgg_register_plugin_hook_handler('entity:url', 'group', 'groups_set_url');
32
	elgg_register_plugin_hook_handler('entity:icon:url', 'group', 'groups_set_icon_url');
33
34
	// Register an icon handler for groups
35
	elgg_register_page_handler('groupicon', 'groups_icon_handler');
36
37
	// Register some actions
38
	$action_base = elgg_get_plugins_path() . 'groups/actions/groups';
39
	elgg_register_action("groups/edit", "$action_base/edit.php");
40
	elgg_register_action("groups/delete", "$action_base/delete.php");
41
	elgg_register_action("groups/featured", "$action_base/featured.php", 'admin');
42
43
	$action_base .= '/membership';
44
	elgg_register_action("groups/invite", "$action_base/invite.php");
45
	elgg_register_action("groups/join", "$action_base/join.php");
46
	elgg_register_action("groups/leave", "$action_base/leave.php");
47
	elgg_register_action("groups/remove", "$action_base/remove.php");
48
	elgg_register_action("groups/killrequest", "$action_base/delete_request.php");
49
	elgg_register_action("groups/killinvitation", "$action_base/delete_invite.php");
50
	elgg_register_action("groups/addtogroup", "$action_base/add.php");
51
52
	// Add some widgets
53
	elgg_register_widget_type('a_users_groups', elgg_echo('groups:widget:membership'), elgg_echo('groups:widgets:description'));
54
55
	elgg_register_widget_type(
56
			'group_activity',
57
			elgg_echo('groups:widget:group_activity:title'),
58
			elgg_echo('groups:widget:group_activity:description'),
59
			array('dashboard'),
60
			true
61
	);
62
63
	// add group activity tool option
64
	add_group_tool_option('activity', elgg_echo('groups:enableactivity'), true);
65
	elgg_extend_view('groups/tool_latest', 'groups/profile/activity_module');
66
67
	// add link to owner block
68
	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'groups_activity_owner_block_menu');
69
70
	// group entity menu
71
	elgg_register_plugin_hook_handler('register', 'menu:entity', 'groups_entity_menu_setup');
72
73
	// group user hover menu
74
	elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'groups_user_entity_menu_setup');
75
76
	// invitation request actions
77
	elgg_register_plugin_hook_handler('register', 'menu:invitationrequest', 'groups_invitationrequest_menu_setup');
78
79
	//extend some views
80
	elgg_extend_view('css/elgg', 'groups/css');
81
	elgg_extend_view('js/elgg', 'groups/js');
82
83
	// Access permissions
84
	elgg_register_plugin_hook_handler('access:collections:write', 'all', 'groups_write_acl_plugin_hook');
85
	elgg_register_plugin_hook_handler('default', 'access', 'groups_access_default_override');
86
87
	// Register profile menu hook
88
	elgg_register_plugin_hook_handler('profile_menu', 'profile', 'activity_profile_menu');
89
90
	// allow ecml in discussion and profiles
91
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'groups_ecml_views_hook');
92
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'groupprofile_ecml_views_hook');
93
94
	// Register a handler for create groups
95
	elgg_register_event_handler('create', 'group', 'groups_create_event_listener');
96
97
	elgg_register_event_handler('join', 'group', 'groups_user_join_event_listener');
98
	elgg_register_event_handler('leave', 'group', 'groups_user_leave_event_listener');
99
	elgg_register_event_handler('pagesetup', 'system', 'groups_setup_sidebar_menus');
100
101
	elgg_register_plugin_hook_handler('access:collections:add_user', 'collection', 'groups_access_collection_override');
102
103
	elgg_register_event_handler('upgrade', 'system', 'groups_run_upgrades');
104
105
	// Add tests
106
	elgg_register_plugin_hook_handler('unit_test', 'system', 'groups_test');
107
}
108
109
/**
110
 * This function loads a set of default fields into the profile, then triggers
111
 * a hook letting other plugins to edit add and delete fields.
112
 *
113
 * Note: This is a system:init event triggered function and is run at a super
114
 * low priority to guarantee that it is called after all other plugins have
115
 * initialized.
116
 */
117
function groups_fields_setup() {
118
119
	$profile_defaults = array(
120
		'description' => 'longtext',
121
		'description2' => 'longtext',
122
		'description3' => 'hidden',
123
		'interests' => 'tags',
124
		//'website' => 'url',
125
	);
126
127
	$profile_defaults = elgg_trigger_plugin_hook('profile:fields', 'group', NULL, $profile_defaults);
128
129
	elgg_set_config('group', $profile_defaults);
130
131
	// register any tag metadata names
132
	foreach ($profile_defaults as $name => $type) {
133
		if ($type == 'tags') {
134
			elgg_register_tag_metadata_name($name);
135
136
			// only shows up in search but why not just set this in en.php as doing it here
137
			// means you cannot override it in a plugin
138
			add_translation(get_current_language(), array("tag_names:$name" => elgg_echo("groups:$name")));
139
		}
140
	}
141
}
142
143
/**
144
 * Configure the groups sidebar menu. Triggered on page setup
145
 *
146
 */
147
function groups_setup_sidebar_menus() {
148
149
	// Get the page owner entity
150
	$page_owner = elgg_get_page_owner_entity();
151
152
	if (elgg_in_context('group_profile')) {
153
		if (!elgg_instanceof($page_owner, 'group')) {
154
			forward('', '404');
155
		}
156
157
		if (elgg_is_logged_in() && $page_owner->canEdit() && !$page_owner->isPublicMembership()) {
158
			$url = elgg_get_site_url() . "groups/requests/{$page_owner->getGUID()}";
159
160
			$count = elgg_get_entities_from_relationship(array(
161
				'type' => 'user',
162
				'relationship' => 'membership_request',
163
				'relationship_guid' => $page_owner->getGUID(),
164
				'inverse_relationship' => true,
165
				'count' => true,
166
			));
167
168
			if ($count) {
169
				$text = elgg_echo('groups:membershiprequests:pending', array($count));
170
			} else {
171
				$text = elgg_echo('groups:membershiprequests');
172
			}
173
174
			elgg_register_menu_item('page', array(
175
				'name' => 'membership_requests',
176
				'text' => $text,
177
				'href' => $url,
178
			));
179
		}
180
	}
181
	/*if (elgg_get_context() == 'groups' && !elgg_instanceof($page_owner, 'group')) {
182
		elgg_register_menu_item('page', array(
183
			'name' => 'groups:all',
184
			'text' => elgg_echo('groups:all'),
185
			'href' => 'groups/all',
186
		));
187
188
		$user = elgg_get_logged_in_user_entity();
189
		if ($user) {
190
			$url =  "groups/owner/$user->username";
191
			$item = new ElggMenuItem('groups:owned', elgg_echo('groups:owned'), $url);
192
			elgg_register_menu_item('page', $item);
193
194
			$url = "groups/member/$user->username";
195
			$item = new ElggMenuItem('groups:member', elgg_echo('groups:yours'), $url);
196
			elgg_register_menu_item('page', $item);
197
198
			$url = "groups/invitations/$user->username";
199
			$invitation_count = groups_get_invited_groups($user->getGUID(), false, array('count' => true));
200
201
			if ($invitation_count) {
202
				$text = elgg_echo('groups:invitations:pending', array($invitation_count));
203
			} else {
204
				$text = elgg_echo('groups:invitations');
205
			}
206
207
			$item = new ElggMenuItem('groups:user:invites', $text, $url);
208
			elgg_register_menu_item('page', $item);
209
		}
210
	}*/
211
}
212
213
/**
214
 * Groups page handler
215
 *
216
 * URLs take the form of
217
 *  All groups:           groups/all
218
 *  User's owned groups:  groups/owner/<username>
219
 *  User's member groups: groups/member/<username>
220
 *  Group profile:        groups/profile/<guid>/<title>
221
 *  New group:            groups/add/<guid>
222
 *  Edit group:           groups/edit/<guid>
223
 *  Group invitations:    groups/invitations/<username>
224
 *  Invite to group:      groups/invite/<guid>
225
 *  Membership requests:  groups/requests/<guid>
226
 *  Group activity:       groups/activity/<guid>
227
 *  Group members:        groups/members/<guid>
228
 *
229
 * @param array $page Array of url segments for routing
230
 * @return bool
231
 */
232
function groups_page_handler($page) {
233
234
	elgg_load_library('elgg:groups');
235
236
	if (!isset($page[0])) {
237
		$page[0] = 'all';
238
	}
239
240
	elgg_push_breadcrumb(elgg_echo('groups'), "groups/all");
241
242
	switch ($page[0]) {
243
		case 'all':
244
			groups_handle_all_page();
245
			break;
246
		case 'search':
247
			groups_search_page();
248
			break;
249
		case 'owner':
250
			groups_handle_owned_page();
251
			break;
252
		case 'member':
253
			set_input('username', $page[1]);
254
			groups_handle_mine_page();
255
			break;
256
		case 'invitations':
257
			set_input('username', $page[1]);
258
			groups_handle_invitations_page();
259
			break;
260
		case 'add':
261
			groups_handle_edit_page('add');
262
			break;
263
		case 'edit':
264
			groups_handle_edit_page('edit', $page[1]);
265
			break;
266
		case 'profile':
267
			groups_handle_profile_page($page[1]);
268
			break;
269
		case 'activity':
270
			groups_handle_activity_page($page[1]);
271
			break;
272
		case 'members':
273
			groups_handle_members_page($page[1]);
274
			break;
275
		case 'invite':
276
			groups_handle_invite_page($page[1]);
277
			break;
278
		case 'requests':
279
			groups_handle_requests_page($page[1]);
280
			break;
281
		case 'stats':
282
			groups_handle_stats_page($page[1]);
283
			break;
284
		case 'about':
285
			elgg_set_page_owner_guid($page[1]);
286
			echo elgg_view('resources/group/about');
287
			break;	
288
		default:
289
			return false;
290
	}
291
	return true;
292
}
293
294
/**
295
 * Handle group icons.
296
 *
297
 * @param array $page
298
 * @return bool
299
 */
300
function groups_icon_handler($page) {
301
302
	// The username should be the file we're getting
303
	if (isset($page[0])) {
304
		set_input('group_guid', $page[0]);
305
	}
306
	if (isset($page[1])) {
307
		set_input('size', $page[1]);
308
	}
309
	// Include the standard profile index
310
	$plugin_dir = elgg_get_plugins_path();
311
	include("$plugin_dir/groups/icon.php");
312
	return true;
313
}
314
315
/**
316
 * Populates the ->getUrl() method for group objects
317
 *
318
 * @param string $hook
319
 * @param string $type
320
 * @param string $url
321
 * @param array  $params
322
 * @return string
323
 */
324
function groups_set_url($hook, $type, $url, $params) {
325
	$entity = $params['entity'];
326
	$title = elgg_get_friendly_title($entity->name);
327
	return "groups/profile/{$entity->guid}/$title";
328
}
329
330
/**
331
 * Override the default entity icon for groups
332
 *
333
 * @param string $hook
334
 * @param string $type
335
 * @param string $url
336
 * @param array  $params
337
 * @return string Relative URL
338
 */
339
function groups_set_icon_url($hook, $type, $url, $params) {
340
	/* @var ElggGroup $group */
341
	$group = $params['entity'];
342
	$size = $params['size'];
343
344
	$icontime = $group->icontime;
345
	// handle missing metadata (pre 1.7 installations)
346
	if (null === $icontime) {
347
		$file = new ElggFile();
348
		$file->owner_guid = $group->owner_guid;
349
		$file->setFilename("groups/" . $group->guid . "large.jpg");
350
		$icontime = $file->exists() ? time() : 0;
351
		create_metadata($group->guid, 'icontime', $icontime, 'integer', $group->owner_guid, ACCESS_PUBLIC);
352
	}
353
	if ($icontime) {
354
		// return thumbnail
355
		return "groupicon/$group->guid/$size/$icontime.jpg";
356
	}
357
358
	return "mod/groups/graphics/default{$size}.gif";
359
}
360
361
/**
362
 * Add owner block link
363
 */
364 View Code Duplication
function groups_activity_owner_block_menu($hook, $type, $return, $params) {
365
	if (elgg_instanceof($params['entity'], 'group')) {
366
		if ($params['entity']->activity_enable != "no") {
367
			$url = "groups/activity/{$params['entity']->guid}";
368
			$item = new ElggMenuItem('activity', elgg_echo('groups:activity'), $url);
369
			$return[] = $item;
370
		}
371
	}
372
373
	return $return;
374
}
375
376
/**
377
 * Add links/info to entity menu particular to group entities
378
 */
379
function groups_entity_menu_setup($hook, $type, $return, $params) {
380
	if (elgg_in_context('widgets')) {
381
		return $return;
382
	}
383
384
	/* @var ElggGroup $entity */
385
	$entity = $params['entity'];
386
	$handler = elgg_extract('handler', $params, false);
387
	if ($handler != 'groups') {
388
		return $return;
389
	}
390
391
	/* @var ElggMenuItem $item */
392
	foreach ($return as $index => $item) {
393 View Code Duplication
		if ( get_group_members($entity->guid, 10, 0, 0, true) > 1 )
394
			if (in_array($item->getName(), array('access', 'edit'))) {
395
				unset($return[$index]);
396
		}
397 View Code Duplication
		if ( get_group_members($entity->guid, 10, 0, 0, true) == 1 )
398
			if (in_array($item->getName(), array('access', 'edit'))) {
399
				unset($return[$index]);
400
		}
401
	}
402
403
	// membership type
404
	if ($entity->isPublicMembership()) {
405
		$mem = elgg_echo("groups:open");
406
	} else {
407
		$mem = elgg_echo("groups:closed");
408
	}
409
410
	$options = array(
411
		'name' => 'membership',
412
		'text' => $mem,
413
		'href' => false,
414
		'priority' => 100,
415
	);
416
	$return[] = ElggMenuItem::factory($options);
417
418
	// number of members
419
	$num_members = $entity->getMembers(array('count' => true));
420
	$members_string = elgg_echo('groups:member');
421
	$options = array(
422
		'name' => 'members',
423
		'text' => $num_members . ' ' . $members_string,
424
		'href' => false,
425
		'priority' => 200,
426
	);
427
	$return[] = ElggMenuItem::factory($options);
428
429
	// feature link
430 View Code Duplication
	if (elgg_is_admin_logged_in()) {
431
		$isFeatured = $entity->featured_group == "yes";
432
433
		$return[] = ElggMenuItem::factory(array(
434
			'name' => 'feature',
435
			'text' => elgg_echo("groups:makefeatured"),
436
			'href' => elgg_add_action_tokens_to_url("action/groups/featured?group_guid={$entity->guid}&action_type=feature"),
437
			'priority' => 300,
438
			'item_class' => $isFeatured ? 'hidden' : '',
439
		));
440
441
		$return[] = ElggMenuItem::factory(array(
442
			'name' => 'unfeature',
443
			'text' => elgg_echo("groups:makeunfeatured"),
444
			'href' => elgg_add_action_tokens_to_url("action/groups/featured?group_guid={$entity->guid}&action_type=unfeature"),
445
			'priority' => 300,
446
			'item_class' => $isFeatured ? '' : 'hidden',
447
		));
448
	}
449
450
	return $return;
451
}
452
453
/**
454
 * Add a remove user link to user hover menu when the page owner is a group
455
 */
456
function groups_user_entity_menu_setup($hook, $type, $return, $params) {
457
	if (elgg_is_logged_in()) {
458
		$group = elgg_get_page_owner_entity();
459
460
		// Check for valid group
461
		if (!elgg_instanceof($group, 'group')) {
462
			return $return;
463
		}
464
465
		$entity = $params['entity'];
466
467
		// Make sure we have a user and that user is a member of the group
468
		if (!elgg_instanceof($entity, 'user') || !$group->isMember($entity)) {
469
			return $return;
470
		}
471
472
		// Add remove link if we can edit the group, and if we're not trying to remove the group owner
473
		if ($group->canEdit() && $group->getOwnerGUID() != $entity->guid) {
474
			$return[] = ElggMenuItem::factory([
475
				'name' => 'removeuser',
476
				'href' => "action/groups/remove?user_guid={$entity->guid}&group_guid={$group->guid}",
477
				'text' => elgg_echo('groups:removeuser'),
478
				'confirm' => true,
479
				'priority' => 999,
480
			]);
481
		}
482
	}
483
484
	return $return;
485
}
486
487
/**
488
 * Groups created so create an access list for it
489
 */
490
function groups_create_event_listener($event, $object_type, $object) {
491
	$ac_name = elgg_echo('groups:group') . ": " . $object->name;
492
	$ac_id = create_access_collection($ac_name, $object->guid);
493
	if ($ac_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $ac_id of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
494
		$object->group_acl = $ac_id;
495
	} else {
496
		// delete group if access creation fails
497
		return false;
498
	}
499
500
	return true;
501
}
502
503
/**
504
 * Return the write access for the current group if the user has write access to it.
505
 */
506
function groups_write_acl_plugin_hook($hook, $entity_type, $returnvalue, $params) {
507
508
	$user_guid = sanitise_int(elgg_extract('user_id', $params), false);
509
	$user = get_user($user_guid);
510
	if (empty($user)) {
511
		return $returnvalue;
512
	}
513
514
	$page_owner = elgg_get_page_owner_entity();
515
	if (!($page_owner instanceof ElggGroup)) {
516
		return $returnvalue;
517
	}
518
519
	if (!$page_owner->canWriteToContainer($user_guid)) {
520
		return $returnvalue;
521
	}
522
523
	// check group content access rules
524
	$allowed_access = array(
525
		ACCESS_PRIVATE
526
	);
527
528
	if ($page_owner->getContentAccessMode() !== ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
529
		$allowed_access[] = ACCESS_LOGGED_IN;
530
		$allowed_access[] = ACCESS_PUBLIC;
531
	}
532
533
	foreach ($returnvalue as $access_id => $access_string) {
534
		if (!in_array($access_id, $allowed_access)) {
535
			unset($returnvalue[$access_id]);
536
		}
537
	}
538
$lang = get_current_language();
539
	// add write access to the group
540
	$returnvalue[$page_owner->group_acl] = elgg_echo('groups:acl', array(gc_explode_translation($page_owner->name,$lang)));
541
542
	return $returnvalue;
543
}
544
545
/**
546
 * Listens to a group join event and adds a user to the group's access control
547
 *
548
 */
549 View Code Duplication
function groups_user_join_event_listener($event, $object_type, $object) {
550
551
	$group = $object['group'];
552
	$user = $object['user'];
553
	$acl = $group->group_acl;
554
555
	add_user_to_access_collection($user->guid, $acl);
556
557
	return true;
558
}
559
560
/**
561
 * Make sure users are added to the access collection
562
 */
563
function groups_access_collection_override($hook, $entity_type, $returnvalue, $params) {
564
	if (isset($params['collection'])) {
565
		if (elgg_instanceof(get_entity($params['collection']->owner_guid), 'group')) {
566
			return true;
567
		}
568
	}
569
}
570
571
/**
572
 * Listens to a group leave event and removes a user from the group's access control
573
 *
574
 */
575 View Code Duplication
function groups_user_leave_event_listener($event, $object_type, $object) {
576
577
	$group = $object['group'];
578
	$user = $object['user'];
579
	$acl = $group->group_acl;
580
581
	remove_user_from_access_collection($user->guid, $acl);
582
583
	return true;
584
}
585
586
/**
587
 * The default access for members only content is this group only. This makes
588
 * for better display of access (can tell it is group only), but does not change
589
 * access to the content.
590
 *
591
 * @param string $hook   Hook name
592
 * @param string $type   Hook type
593
 * @param int    $access Current default access
594
 * @return int
595
 */
596
function groups_access_default_override($hook, $type, $access) {
597
	$page_owner = elgg_get_page_owner_entity();
598
599
	if (elgg_instanceof($page_owner, 'group')) {
600
		if ($page_owner->getContentAccessMode() == ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
601
			$access = $page_owner->group_acl;
602
		}
603
	}
604
605
	return $access;
606
}
607
608
/**
609
 * Grabs groups by invitations
610
 * Have to override all access until there's a way override access to getter functions.
611
 *
612
 * @param int   $user_guid    The user's guid
613
 * @param bool  $return_guids Return guids rather than ElggGroup objects
614
 * @param array $options      Additional options
615
 *
616
 * @return mixed ElggGroups or guids depending on $return_guids, or count
617
 */
618
function groups_get_invited_groups($user_guid, $return_guids = false, $options = array()) {
619
620
	$ia = elgg_set_ignore_access(true);
621
622
	$defaults = array(
623
		'relationship' => 'invited',
624
		'relationship_guid' => (int) $user_guid,
625
		'inverse_relationship' => true,
626
		'limit' => 0,
627
	);
628
629
	$options = array_merge($defaults, $options);
630
	$groups = elgg_get_entities_from_relationship($options);
631
632
	elgg_set_ignore_access($ia);
633
634
	if ($return_guids) {
635
		$guids = array();
636
		foreach ($groups as $group) {
637
			$guids[] = $group->getGUID();
638
		}
639
640
		return $guids;
641
	}
642
643
	return $groups;
644
}
645
646
/**
647
 * Join a user to a group, add river event, clean-up invitations
648
 *
649
 * @param ElggGroup $group
650
 * @param ElggUser  $user
651
 * @return bool
652
 */
653
function groups_join_group($group, $user) {
654
655
	// access ignore so user can be added to access collection of invisible group
656
	$ia = elgg_set_ignore_access(TRUE);
657
	$result = $group->join($user);
658
	elgg_set_ignore_access($ia);
659
660
	if ($result) {
661
		// flush user's access info so the collection is added
662
		get_access_list($user->guid, 0, true);
663
664
		// Remove any invite or join request flags
665
		remove_entity_relationship($group->guid, 'invited', $user->guid);
666
		remove_entity_relationship($user->guid, 'membership_request', $group->guid);
667
668
		elgg_create_river_item(array(
669
			'view' => 'river/relationship/member/create',
670
			'action_type' => 'join',
671
			'subject_guid' => $user->guid,
672
			'object_guid' => $group->guid,
673
		));
674
675
		return true;
676
	}
677
678
	return false;
679
}
680
681
/**
682
 * Function to use on groups for access. It will house private, loggedin, public,
683
 * and the group itself. This is when you don't want other groups or access lists
684
 * in the access options available.
685
 *
686
 * @return array
687
 */
688
function group_access_options($group) {
689
	$access_array = array(
690
		ACCESS_PRIVATE => 'private',
691
		ACCESS_LOGGED_IN => 'logged in users',
692
		ACCESS_PUBLIC => 'public',
693
		$group->group_acl => elgg_echo('groups:acl', array($group->name)),
694
	);
695
	return $access_array;
696
}
697
698
function activity_profile_menu($hook, $entity_type, $return_value, $params) {
699
700
	if ($params['owner'] instanceof ElggGroup) {
701
		$return_value[] = array(
702
			'text' => elgg_echo('groups:activity'),
703
			'href' => "groups/activity/{$params['owner']->getGUID()}"
704
		);
705
	}
706
	return $return_value;
707
}
708
709
/**
710
 * Parse ECML on group discussion views
711
 */
712
function groups_ecml_views_hook($hook, $entity_type, $return_value, $params) {
713
	$return_value['forum/viewposts'] = elgg_echo('groups:ecml:discussion');
714
715
	return $return_value;
716
}
717
718
/**
719
 * Parse ECML on group profiles
720
 */
721
function groupprofile_ecml_views_hook($hook, $entity_type, $return_value, $params) {
722
	$return_value['groups/groupprofile'] = elgg_echo('groups:ecml:groupprofile');
723
724
	return $return_value;
725
}
726
727
728
729
/**
730
 * Discussion
731
 *
732
 */
733
734
elgg_register_event_handler('init', 'system', 'discussion_init');
735
736
/**
737
 * Initialize the discussion component
738
 */
739
function discussion_init() {
740
741
	elgg_register_library('elgg:discussion', elgg_get_plugins_path() . 'groups/lib/discussion.php');
742
743
	elgg_register_page_handler('discussion', 'discussion_page_handler');
744
745
	elgg_register_plugin_hook_handler('entity:url', 'object', 'discussion_set_topic_url');
746
747
	// commenting not allowed on discussion topics (use a different annotation)
748
	elgg_register_plugin_hook_handler('permissions_check:comment', 'object', 'discussion_comment_override');
749
	elgg_register_plugin_hook_handler('permissions_check', 'object', 'discussion_can_edit_reply');
750
751
	// discussion reply menu
752
	elgg_register_plugin_hook_handler('register', 'menu:entity', 'discussion_reply_menu_setup');
753
754
	// allow non-owners to add replies to group discussion
755
	elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'discussion_reply_container_permissions_override');
756
757
	elgg_register_event_handler('update:after', 'object', 'discussion_update_reply_access_ids');
758
759
	$action_base = elgg_get_plugins_path() . 'groups/actions/discussion';
760
	elgg_register_action('discussion/save', "$action_base/save.php");
761
	elgg_register_action('discussion/delete', "$action_base/delete.php");
762
	elgg_register_action('discussion/reply/save', "$action_base/reply/save.php");
763
	elgg_register_action('discussion/reply/delete', "$action_base/reply/delete.php");
764
765
	// add link to owner block
766
	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'discussion_owner_block_menu');
767
768
	// Register for search.
769
	elgg_register_entity_type('object', 'groupforumtopic');
770
	elgg_register_plugin_hook_handler('search', 'object:groupforumtopic', 'discussion_search_groupforumtopic');
771
772
	// because replies are not comments, need of our menu item
773
	elgg_register_plugin_hook_handler('register', 'menu:river', 'discussion_add_to_river_menu');
774
775
	// add the forum tool option
776
	add_group_tool_option('forum', elgg_echo('groups:enableforum'), true);
777
	elgg_extend_view('groups/tool_latest', 'discussion/group_module');
778
779
	$discussion_js_path = elgg_get_site_url() . 'mod/groups/views/default/js/discussion/';
780
	elgg_register_js('elgg.discussion', $discussion_js_path . 'discussion.js');
781
782
	elgg_register_ajax_view('ajax/discussion/reply/edit');
783
784
	// notifications
785
	elgg_register_plugin_hook_handler('get', 'subscriptions', 'discussion_get_subscriptions');
786
	elgg_register_notification_event('object', 'groupforumtopic');
787
	elgg_register_plugin_hook_handler('prepare', 'notification:create:object:groupforumtopic', 'discussion_prepare_notification');
788
	elgg_register_notification_event('object', 'discussion_reply');
789
	elgg_register_plugin_hook_handler('prepare', 'notification:create:object:discussion_reply', 'discussion_prepare_reply_notification');
790
}
791
792
/**
793
 * Discussion page handler
794
 *
795
 * URLs take the form of
796
 *  All topics in site:    discussion/all
797
 *  List topics in forum:  discussion/owner/<guid>
798
 *  View discussion topic: discussion/view/<guid>
799
 *  Add discussion topic:  discussion/add/<guid>
800
 *  Edit discussion topic: discussion/edit/<guid>
801
 *
802
 * @param array $page Array of url segments for routing
803
 * @return bool
804
 */
805
function discussion_page_handler($page) {
806
807
	elgg_load_library('elgg:discussion');
808
809
	if (!isset($page[0])) {
810
		$page[0] = 'all';
811
	}
812
813
	elgg_push_breadcrumb(elgg_echo('discussion'), 'discussion/all');
814
815
	switch ($page[0]) {
816
		case 'all':
817
			discussion_handle_all_page();
818
			break;
819
		case 'owner':
820
			discussion_handle_list_page(elgg_extract(1, $page));
821
			break;
822
		case 'add':
823
			discussion_handle_edit_page('add', elgg_extract(1, $page));
824
			break;
825
		case 'reply':
826
			switch (elgg_extract(1, $page)) {
827
				case 'edit':
828
					discussion_handle_reply_edit_page('edit', elgg_extract(2, $page));
829
					break;
830
				case 'view':
831
					discussion_redirect_to_reply(elgg_extract(2, $page), elgg_extract(3, $page));
832
					break;
833
				default:
834
					return false;
835
			}
836
			break;
837
		case 'edit':
838
			discussion_handle_edit_page('edit', elgg_extract(1, $page));
839
			break;
840
		case 'view':
841
			discussion_handle_view_page(elgg_extract(1, $page));
842
			break;
843
		default:
844
			return false;
845
	}
846
	return true;
847
}
848
849
/**
850
 * Redirect to the reply in context of the containing topic
851
 *
852
 * @param int $reply_guid    GUID of the reply
853
 * @param int $fallback_guid GUID of the topic
854
 *
855
 * @return void
856
 * @access private
857
 */
858
function discussion_redirect_to_reply($reply_guid, $fallback_guid) {
859
	$fail = function () {
860
		register_error(elgg_echo('discussion:reply:error:notfound'));
861
		forward(REFERER);
862
	};
863
864
	$reply = get_entity($reply_guid);
865 View Code Duplication
	if (!$reply) {
866
		// try fallback
867
		$fallback = get_entity($fallback_guid);
868
		if (!elgg_instanceof($fallback, 'object', 'groupforumtopic')) {
869
			$fail();
870
		}
871
872
		register_error(elgg_echo('discussion:reply:error:notfound_fallback'));
873
		forward($fallback->getURL());
874
	}
875
876
	if (!$reply instanceof ElggDiscussionReply) {
877
		$fail();
878
	}
879
880
	// start with topic URL
881
	$topic = $reply->getContainerEntity();
882
883
	// this won't work with threaded comments, but core doesn't support that yet
884
	$count = elgg_get_entities([
885
		'type' => 'object',
886
		'subtype' => $reply->getSubtype(),
887
		'container_guid' => $topic->guid,
888
		'count' => true,
889
		'wheres' => ["e.guid < " . (int)$reply->guid],
890
	]);
891
	$limit = (int)get_input('limit', 0);
892
	if (!$limit) {
893
		$limit = _elgg_services()->config->get('default_limit');
894
	}
895
	$offset = floor($count / $limit) * $limit;
896
	if (!$offset) {
897
		$offset = null;
898
	}
899
900
	$url = elgg_http_add_url_query_elements($topic->getURL(), [
901
			'offset' => $offset,
902
		]) . "#elgg-object-{$reply->guid}";
903
904
	forward($url);
905
}
906
907
/**
908
 * Override the url for discussion topics and replies
909
 *
910
 * Discussion replies do not have their own page so their url is
911
 * the same as the topic url.
912
 *
913
 * @param string $hook
914
 * @param string $type
915
 * @param string $url
916
 * @param array  $params
917
 * @return string
918
 */
919
function discussion_set_topic_url($hook, $type, $url, $params) {
920
	$entity = $params['entity'];
921
922
	if (!$entity instanceof ElggObject) {
923
		return;
924
	}
925
926
	if ($entity->getSubtype() === 'groupforumtopic') {
927
		$title = elgg_get_friendly_title($entity->title);
928
		return "discussion/view/{$entity->guid}/{$title}";
929
	}
930
931
	if (!$entity instanceof ElggDiscussionReply) {
932
		return;
933
	}
934
935
	$topic = $entity->getContainerEntity();
936
937
	return "discussion/reply/view/{$entity->guid}/{$topic->guid}";
938
}
939
940
/**
941
 * We don't want people commenting on topics in the river
942
 *
943
 * @param string $hook
944
 * @param string $type
945
 * @param string $return
946
 * @param array  $params
947
 * @return bool
948
 */
949
function discussion_comment_override($hook, $type, $return, $params) {
950
	if (elgg_instanceof($params['entity'], 'object', 'groupforumtopic')) {
951
		return false;
952
	}
953
}
954
955
/**
956
 * Add owner block link
957
 *
958
 * @param string          $hook    'register'
959
 * @param string          $type    'menu:owner_block'
960
 * @param ElggMenuItem[]  $return
961
 * @param array           $params
962
 * @return ElggMenuItem[]  $return
963
 */
964 View Code Duplication
function discussion_owner_block_menu($hook, $type, $return, $params) {
965
	if (elgg_instanceof($params['entity'], 'group')) {
966
		if ($params['entity']->forum_enable != "no") {
967
			$url = "discussion/owner/{$params['entity']->guid}";
968
			$item = new ElggMenuItem('discussion', elgg_echo('discussion:group'), $url);
969
			$return[] = $item;
970
		}
971
	}
972
973
	return $return;
974
}
975
976
/**
977
 * Set up menu items for river items
978
 *
979
 * Add reply button for discussion topic. Remove the possibility
980
 * to comment on a discussion reply.
981
 *
982
 * @param string         $hook   'register'
983
 * @param string         $type   'menu:river'
984
 * @param ElggMenuItem[] $return
985
 * @param array          $params
986
 * @return ElggMenuItem[] $return
987
 */
988
function discussion_add_to_river_menu($hook, $type, $return, $params) {
989
	if (!elgg_is_logged_in() || elgg_in_context('widgets')) {
990
		return $return;
991
	}
992
993
	$item = $params['item'];
994
	$object = $item->getObjectEntity();
995
996
	if (elgg_instanceof($object, 'object', 'groupforumtopic')) {
997
		$group = $object->getContainerEntity();
998
999 View Code Duplication
		if ($group && ($group->canWriteToContainer() || elgg_is_admin_logged_in())) {
1000
				$options = array(
1001
				'name' => 'reply',
1002
				'href' => "#discussion-reply-{$object->guid}",
1003
				'text' => elgg_view_icon('speech-bubble'),
1004
				'title' => elgg_echo('reply:this'),
1005
				'rel' => 'toggle',
1006
				'priority' => 50,
1007
			);
1008
			$return[] = ElggMenuItem::factory($options);
1009
		}
1010
	} else {
1011
		if (elgg_instanceof($object, 'object', 'discussion_reply', 'ElggDiscussionReply')) {
1012
			// Group discussion replies cannot be commented
1013
			foreach ($return as $key => $item) {
1014
				if ($item->getName() === 'comment') {
1015
					unset($return[$key]);
1016
				}
1017
			}
1018
		}
1019
	}
1020
1021
	return $return;
1022
}
1023
1024
/**
1025
 * Prepare a notification message about a new discussion topic
1026
 *
1027
 * @param string                          $hook         Hook name
1028
 * @param string                          $type         Hook type
1029
 * @param Elgg\Notifications\Notification $notification The notification to prepare
1030
 * @param array                           $params       Hook parameters
1031
 * @return Elgg\Notifications\Notification
1032
 */
1033 View Code Duplication
function discussion_prepare_notification($hook, $type, $notification, $params) {
1034
	$entity = $params['event']->getObject();
1035
	$owner = $params['event']->getActor();
1036
	$recipient = $params['recipient'];
1037
	$language = $params['language'];
1038
	$method = $params['method'];
1039
1040
	$descr = $entity->description;
1041
	$title = $entity->title;
1042
	$group = $entity->getContainerEntity();
1043
1044
	$notification->subject = elgg_echo('discussion:topic:notify:subject', array($title), $language);
1045
	$notification->body = elgg_echo('discussion:topic:notify:body', array(
1046
		$owner->name,
1047
		$group->name,
1048
		$title,
1049
		$descr,
1050
		$entity->getURL()
1051
	), $language);
1052
	$notification->summary = elgg_echo('discussion:topic:notify:summary', array($entity->title), $language);
1053
1054
	return $notification;
1055
}
1056
1057
/**
1058
 * Prepare a notification message about a new discussion reply
1059
 *
1060
 * @param string                          $hook         Hook name
1061
 * @param string                          $type         Hook type
1062
 * @param Elgg\Notifications\Notification $notification The notification to prepare
1063
 * @param array                           $params       Hook parameters
1064
 * @return Elgg\Notifications\Notification
1065
 */
1066
function discussion_prepare_reply_notification($hook, $type, $notification, $params) {
1067
	$reply = $params['event']->getObject();
1068
	$topic = $reply->getContainerEntity();
1069
	$poster = $reply->getOwnerEntity();
1070
	$group = $topic->getContainerEntity();
1071
	$language = elgg_extract('language', $params);
1072
1073
	$notification->subject = elgg_echo('discussion:reply:notify:subject', array($topic->title), $language);
1074
	$notification->body = elgg_echo('discussion:reply:notify:body', array(
1075
		$poster->name,
1076
		$topic->title,
1077
		$group->name,
1078
		$reply->description,
1079
		$reply->getURL(),
1080
	), $language);
1081
	$notification->summary = elgg_echo('discussion:reply:notify:summary', array($topic->title), $language);
1082
1083
	return $notification;
1084
}
1085
1086
/**
1087
 * Get subscriptions for group notifications
1088
 *
1089
 * @param string $hook          'get'
1090
 * @param string $type          'subscriptions'
1091
 * @param array  $subscriptions Array containing subscriptions in the form
1092
 *                       <user guid> => array('email', 'site', etc.)
1093
 * @param array  $params        Hook parameters
1094
 * @return array
1095
 */
1096
function discussion_get_subscriptions($hook, $type, $subscriptions, $params) {
1097
	$reply = $params['event']->getObject();
1098
1099
	if (!elgg_instanceof($reply, 'object', 'discussion_reply', 'ElggDiscussionReply')) {
1100
		return $subscriptions;
1101
	}
1102
1103
	$group_guid = $reply->getContainerEntity()->container_guid;
1104
	$group_subscribers = elgg_get_subscriptions_for_container($group_guid);
1105
1106
	return ($subscriptions + $group_subscribers);
1107
}
1108
1109
/**
1110
 * A simple function to see who can edit a group discussion post
1111
 *
1112
 * @param ElggComment $entity      the  comment $entity
1113
 * @param ELggUser    $group_owner user who owns the group $group_owner
1114
 * @return boolean
1115
 */
1116
function groups_can_edit_discussion($entity, $group_owner) {
1117
1118
	//logged in user
1119
	$user = elgg_get_logged_in_user_guid();
1120
1121
	if (($entity->owner_guid == $user) || $group_owner == $user || elgg_is_admin_logged_in()) {
1122
		return true;
1123
	} else {
1124
		return false;
1125
	}
1126
}
1127
1128
/**
1129
 * Process upgrades for the groups plugin
1130
 */
1131
function groups_run_upgrades() {
1132
	$path = elgg_get_plugins_path() . 'groups/upgrades/';
1133
	$files = elgg_get_upgrade_files($path);
1134
	foreach ($files as $file) {
1135
		include "$path{$file}";
1136
	}
1137
}
1138
1139
/**
1140
 * Allow group owner and discussion owner to edit discussion replies.
1141
 *
1142
 * @param string  $hook   'permissions_check'
1143
 * @param string  $type   'object'
1144
 * @param boolean $return
1145
 * @param array   $params Array('entity' => ElggEntity, 'user' => ElggUser)
1146
 * @return boolean True if user is discussion or group owner
1147
 */
1148
function discussion_can_edit_reply($hook, $type, $return, $params) {
1149
	/** @var $reply ElggEntity */
1150
	$reply = $params['entity'];
1151
	$user = $params['user'];
1152
1153
	if (!elgg_instanceof($reply, 'object', 'discussion_reply', 'ElggDiscussionReply')) {
1154
		return $return;
1155
	}
1156
1157
	if ($reply->owner_guid == $user->guid) {
1158
	    return true;
1159
	}
1160
1161
	$discussion = $reply->getContainerEntity();
1162
	if ($discussion->owner_guid == $user->guid) {
1163
		return true;
1164
	}
1165
1166
	$group = $discussion->getContainerEntity();
1167
	if (elgg_instanceof($group, 'group') && $group->owner_guid == $user->guid) {
1168
		return true;
1169
	}
1170
1171
	return false;
1172
}
1173
1174
/**
1175
 * Allow group members to post to a group discussion
1176
 *
1177
 * @param string $hook   'container_permissions_check'
1178
 * @param string $type   'object'
1179
 * @param array  $return
1180
 * @param array  $params Array with container, user and subtype
1181
 * @return boolean $return
1182
 */
1183
function discussion_reply_container_permissions_override($hook, $type, $return, $params) {
1184
	/** @var $container ElggEntity */
1185
	$container = $params['container'];
1186
	$user = $params['user'];
1187
1188
	if (elgg_instanceof($container, 'object', 'groupforumtopic')) {
1189
		$group = $container->getContainerEntity();
1190
1191
		if ($group->canWriteToContainer($user->guid) && $params['subtype'] === 'discussion_reply') {
1192
			return true;
1193
		}
1194
	}
1195
1196
	return $return;
1197
}
1198
1199
/**
1200
 * Update access_id of discussion replies when topic access_id is updated.
1201
 *
1202
 * @param string     $event  'update'
1203
 * @param string     $type   'object'
1204
 * @param ElggObject $object ElggObject
1205
 */
1206
function discussion_update_reply_access_ids($event, $type, $object) {
1207
	if (elgg_instanceof($object, 'object', 'groupforumtopic')) {
1208
		$ia = elgg_set_ignore_access(true);
1209
		$options = array(
1210
			'type' => 'object',
1211
			'subtype' => 'discussion_reply',
1212
			'container_guid' => $object->getGUID(),
1213
			'limit' => 0,
1214
		);
1215
		$batch = new ElggBatch('elgg_get_entities', $options);
1216
		foreach ($batch as $reply) {
1217
			if ($reply->access_id == $object->access_id) {
1218
				// Assume access_id of the replies is up-to-date
1219
				break;
1220
			}
1221
1222
			// Update reply access_id
1223
			$reply->access_id = $object->access_id;
1224
			$reply->save();
1225
		}
1226
1227
		elgg_set_ignore_access($ia);
1228
	}
1229
}
1230
1231
/**
1232
 * Set up discussion reply entity menu
1233
 *
1234
 * @param string          $hook   'register'
1235
 * @param string          $type   'menu:entity'
1236
 * @param ElggMenuItem[]  $return
1237
 * @param array           $params
1238
 * @return ElggMenuItem[] $return
1239
 */
1240
function discussion_reply_menu_setup($hook, $type, $return, $params) {
1241
	/** @var $reply ElggEntity */
1242
	$reply = elgg_extract('entity', $params);
1243
1244
	if (empty($reply) || !elgg_instanceof($reply, 'object', 'discussion_reply')) {
1245
		return $return;
1246
	}
1247
1248
	if (!elgg_is_logged_in()) {
1249
		return $return;
1250
	}
1251
1252
	if (elgg_in_context('widgets')) {
1253
		return $return;
1254
	}
1255
1256
	// Reply has the same access as the topic so no need to view it
1257
	$remove = array('access');
1258
1259
	// Allow discussion topic owner, group owner and admins to edit and delete
1260
	if ($reply->canEdit() && !elgg_in_context('activity')) {
1261
1262
	$user = elgg_get_logged_in_user_entity();
1263
    $page_owner = elgg_get_page_owner_entity();
1264
	if($page_owner!=''||$page_owner!=null){	
1265
	if($entity->owner_guid == $user['guid'] || elgg_is_admin_logged_in() || ($page_owner instanceof ElggGroup && $page_owner->getOwnerGUID() == $user['guid']) || $page_owner->canEdit()){
0 ignored issues
show
The variable $entity does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1266
                    
1267
			$return[] = ElggMenuItem::factory(array(
1268
				'name' => 'edit',
1269
				'text' => elgg_echo('edit'),
1270
				'href' => "discussion/reply/edit/{$reply->guid}",
1271
				'priority' => 150,
1272
			));
1273
1274
			$return[] = ElggMenuItem::factory(array(
1275
				'name' => 'delete',
1276
				'text' => elgg_view_icon('delete'),
1277
				'href' => "action/discussion/reply/delete?guid={$reply->guid}",
1278
				'priority' => 150,
1279
				'is_action' => true,
1280
				'confirm' => elgg_echo('deleteconfirm'),
1281
			));
1282
		}
1283
	}
1284
	} else {
1285
		// Edit and delete links can be removed from all other users
1286
		$remove[] = 'edit';
1287
		$remove[] = 'delete';
1288
	}
1289
1290
	// Remove unneeded menu items
1291
	foreach ($return as $key => $item) {
1292
		if (in_array($item->getName(), $remove)) {
1293
			unset($return[$key]);
1294
		}
1295
	}
1296
1297
	return $return;
1298
}
1299
1300
1301
/**
1302
 * Runs unit tests for groups
1303
 *
1304
 * @return array
1305
 */
1306
function groups_test($hook, $type, $value, $params) {
1307
	global $CONFIG;
1308
	$value[] = $CONFIG->pluginspath . 'groups/tests/write_access.php';
1309
	return $value;
1310
}
1311
1312
/**
1313
 * Search in both forumtopics and topic replies
1314
 *
1315
 * @param string $hook   the name of the hook
1316
 * @param string $type   the type of the hook
1317
 * @param mixed  $value  the current return value
1318
 * @param array  $params supplied params
1319
 */
1320
function discussion_search_groupforumtopic($hook, $type, $value, $params) {
1321
1322
	if (empty($params) || !is_array($params)) {
1323
		return $value;
1324
	}
1325
1326
	$subtype = elgg_extract("subtype", $params);
1327
	if (empty($subtype) || ($subtype !== "groupforumtopic")) {
1328
		return $value;
1329
	}
1330
1331
	unset($params["subtype"]);
1332
	$params["subtypes"] = array("groupforumtopic", "discussion_reply");
1333
1334
	// trigger the 'normal' object search as it can handle the added options
1335
	return elgg_trigger_plugin_hook('search', 'object', $params, array());
1336
}
1337
1338
/**
1339
 * Setup invitation request actions
1340
 *
1341
 * @param string $hook   "register"
1342
 * @param string $type   "menu:invitationrequest"
1343
 * @param array  $menu   Menu items
1344
 * @param array  $params Hook params
1345
 * @return array
1346
 */
1347
function groups_invitationrequest_menu_setup($hook, $type, $menu, $params) {
1348
1349
	$group = elgg_extract('entity', $params);
1350
	$user = elgg_extract('user', $params);
1351
1352
	if (!$group instanceof \ElggGroup) {
1353
		return $menu;
1354
	}
1355
1356
	if (!$user instanceof \ElggUser || !$user->canEdit()) {
1357
		return $menu;
1358
	}
1359
1360
	$accept_url = elgg_http_add_url_query_elements('action/groups/join', array(
1361
		'user_guid' => $user->guid,
1362
		'group_guid' => $group->guid,
1363
	));
1364
1365
	$menu[] = \ElggMenuItem::factory(array(
1366
		'name' => 'accept',
1367
		'href' => $accept_url,
1368
		'is_action' => true,
1369
		'text' => elgg_echo('accept'),
1370
		'link_class' => 'elgg-button elgg-button-submit',
1371
		'is_trusted' => true,
1372
	));
1373
1374
	$delete_url = elgg_http_add_url_query_elements('action/groups/killinvitation', array(
1375
		'user_guid' => $user->guid,
1376
		'group_guid' => $group->guid,
1377
	));
1378
1379
	$menu[] = \ElggMenuItem::factory(array(
1380
		'name' => 'delete',
1381
		'href' => $delete_url,
1382
		'is_action' => true,
1383
		'confirm' => elgg_echo('groups:invite:remove:check'),
1384
		'text' => elgg_echo('delete'),
1385
		'link_class' => 'elgg-button elgg-button-delete mlm',
1386
	));
1387
1388
	return $menu;
1389
}
1390