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

mod/groups/start.php (1 issue)

1
<?php
2
/**
3
 * Elgg groups plugin
4
 *
5
 * @package ElggGroups
6
 */
7
8
/**
9
 * Initialize the groups plugin
10
 *
11
 * @return void
12
 */
13
function groups_init() {
14
	
15 31
	elgg_extend_view('object/elements/imprint/contents', 'groups/imprint/member_count');
16 31
	elgg_extend_view('object/elements/imprint/contents', 'groups/imprint/membership_type');
17
	
18
	// Set up the menu
19 31
	$item = new ElggMenuItem('groups', elgg_echo('groups'), 'groups/all');
20 31
	elgg_register_menu_item('site', $item);
21
22
	// Register a page handler, so we can have nice URLs
23 31
	elgg_register_page_handler('groups', 'groups_page_handler');
0 ignored issues
show
Deprecated Code introduced by Evan Winslow
The function elgg_register_page_handler() has been deprecated: 3.0 ( Ignorable by Annotation )

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

23
	/** @scrutinizer ignore-deprecated */ elgg_register_page_handler('groups', 'groups_page_handler');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
24
25
	// Register URL handlers for groups
26 31
	elgg_register_plugin_hook_handler('entity:url', 'group', 'groups_set_url');
27 31
	elgg_register_plugin_hook_handler('entity:icon:sizes', 'group', 'groups_set_icon_sizes');
28
29
	// add group activity tool option
30 31
	if (elgg_get_plugin_setting('allow_activity', 'groups') === 'yes') {
31 13
		add_group_tool_option('activity', elgg_echo('groups:enableactivity'), true);
32 13
		elgg_extend_view('groups/tool_latest', 'groups/profile/activity_module');
33
	}
34
35
	// add link to owner block
36 31
	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'groups_activity_owner_block_menu');
37
38
	// group entity menu
39 31
	elgg_register_plugin_hook_handler('register', 'menu:entity', 'groups_entity_menu_setup');
40
41
	// group user hover menu
42 31
	elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'groups_user_entity_menu_setup');
43
44
	// invitation request actions
45 31
	elgg_register_plugin_hook_handler('register', 'menu:invitationrequest', 'groups_invitationrequest_menu_setup');
46
47
	// group members tabs
48 31
	elgg_register_plugin_hook_handler('register', 'menu:groups_members', 'groups_members_menu_setup');
49
	
50
	// topbar menu
51 31
	elgg_register_plugin_hook_handler('register', 'menu:topbar', '_groups_topbar_menu_setup');
52
53
	//extend some views
54 31
	elgg_extend_view('elgg.css', 'groups/css');
55
56
	// Access permissions
57 31
	elgg_register_plugin_hook_handler('access:collections:write', 'all', 'groups_write_acl_plugin_hook', 600);
58 31
	elgg_register_plugin_hook_handler('default', 'access', 'groups_access_default_override');
59 31
	elgg_register_plugin_hook_handler('access_collection:name', 'access_collection', 'groups_set_access_collection_name');
60
61
	// allow ecml in profiles
62 31
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'groupprofile_ecml_views_hook');
63
64
	// Register a handler for create groups
65 31
	elgg_register_event_handler('create', 'group', 'groups_create_event_listener');
66 31
	elgg_register_event_handler('update:after', 'group', 'groups_update_event_listener');
67
68 31
	elgg_register_event_handler('join', 'group', 'groups_user_join_event_listener');
69 31
	elgg_register_event_handler('leave', 'group', 'groups_user_leave_event_listener');
70
71
	// allow to be liked
72 31
	elgg_register_plugin_hook_handler('likes:is_likable', 'group:', 'Elgg\Values::getTrue');
73
74
	// Help core resolve page owner guids from group routes
75
	// Registered with an earlier priority to be called before default_page_owner_handler()
76 31
	elgg_register_plugin_hook_handler('page_owner', 'system', 'groups_default_page_owner_handler', 400);
77
78
	// Setup filter tabs on /groups/all page
79 31
	elgg_register_plugin_hook_handler('register', 'menu:filter:groups/all', 'groups_setup_filter_tabs');
80
81 31
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu_group_profile');
82 31
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu');
83 31
	elgg_register_plugin_hook_handler('register', 'menu:title', '_groups_title_menu');
84 31
}
85
86
/**
87
 * This function loads a set of default fields into the profile, then triggers
88
 * a hook letting other plugins to edit add and delete fields.
89
 *
90
 * Note: This is a system:init event triggered function and is run at a super
91
 * low priority to guarantee that it is called after all other plugins have
92
 * initialized.
93
 *
94
 * @return void
95
 */
96
function groups_fields_setup() {
97
98
	$profile_defaults = [
99 31
		'description' => 'longtext',
100
		'briefdescription' => 'text',
101
		'interests' => 'tags',
102
	];
103
104 31
	$profile_defaults = elgg_trigger_plugin_hook('profile:fields', 'group', null, $profile_defaults);
105
106 31
	elgg_set_config('group', $profile_defaults);
107
108
	// register any tag metadata names
109 31
	foreach ($profile_defaults as $name => $type) {
110 31
		if ($type == 'tags') {
111 31
			elgg_register_tag_metadata_name($name);
112
113
			// only shows up in search but why not just set this in en.php as doing it here
114
			// means you cannot override it in a plugin
115 31
			add_translation(get_current_language(), ["tag_names:$name" => elgg_echo("groups:$name")]);
116
		}
117
	}
118 31
}
119
120
/**
121
 * Register menu items for the page menu
122
 *
123
 * @param string         $hook   'register'
124
 * @param string         $type   'menu:page'
125
 * @param ElggMenuItem[] $return current return value
126
 * @param array          $params supplied params
127
 *
128
 * @return void|ElggMenuItem[]
129
 *
130
 * @access private
131
 * @since 3.0
132
 */
133
function _groups_page_menu_group_profile($hook, $type, $return, $params) {
134
	
135 1
	if (!elgg_in_context('group_profile') || !elgg_is_logged_in()) {
136 1
		return;
137
	}
138
	
139
	// Get the page owner entity
140
	$page_owner = elgg_get_page_owner_entity();
141
	if (!($page_owner instanceof ElggGroup)) {
142
		return;
143
	}
144
	
145
	if (!$page_owner->canEdit() || $page_owner->isPublicMembership()) {
146
		return;
147
	}
148
	
149
	$count = elgg_get_entities([
150
		'type' => 'user',
151
		'relationship' => 'membership_request',
152
		'relationship_guid' => $page_owner->guid,
153
		'inverse_relationship' => true,
154
		'count' => true,
155
	]);
156
157
	$text = elgg_echo('groups:membershiprequests');
158
	$title = $text;
159
	if ($count) {
160
		$title = elgg_echo('groups:membershiprequests:pending', [$count]);
161
	}
162
	
163
	$return[] = \ElggMenuItem::factory([
164
		'name' => 'membership_requests',
165
		'text' => $text,
166
		'badge' => $count ? $count : null,
167
		'title' => $title,
168
		'href' => "groups/requests/{$page_owner->guid}",
169
	]);
170
	
171
	return $return;
172
}
173
174
/**
175
 * Register menu items for the page menu
176
 *
177
 * @param string         $hook   'register'
178
 * @param string         $type   'menu:page'
179
 * @param ElggMenuItem[] $return current return value
180
 * @param array          $params supplied params
181
 *
182
 * @return void|ElggMenuItem[]
183
 *
184
 * @access private
185
 * @since 3.0
186
 */
187
function _groups_page_menu($hook, $type, $return, $params) {
188
	
189 1
	if (elgg_get_context() !== 'groups') {
190 1
		return;
191
	}
192
	
193
	// Get the page owner entity
194
	$page_owner = elgg_get_page_owner_entity();
195
	if ($page_owner instanceof ElggGroup) {
196
		return;
197
	}
198
	
199
	$return[] = \ElggMenuItem::factory([
200
		'name' => 'groups:all',
201
		'text' => elgg_echo('groups:all'),
202
		'href' => 'groups/all',
203
	]);
204
205
	$user = elgg_get_logged_in_user_entity();
206
	if (!$user) {
207
		return $return;
208
	}
209
	
210
	$return[] = \ElggMenuItem::factory([
211
		'name' => 'groups:owned',
212
		'text' => elgg_echo('groups:owned'),
213
		'href' => "groups/owner/$user->username",
214
	]);
215
	
216
	$return[] = \ElggMenuItem::factory([
217
		'name' => 'groups:member',
218
		'text' => elgg_echo('groups:yours'),
219
		'href' => "groups/member/$user->username",
220
	]);
221
222
	$invitation_count = groups_get_invited_groups($user->guid, false, ['count' => true]);
223
224
	// Invitations
225
	$text = elgg_echo('groups:invitations');
226
	$title = $text;
227
	if ($invitation_count) {
228
		$title = elgg_echo('groups:invitations:pending', [$invitation_count]);
229
	}
230
231
	$return[] = \ElggMenuItem::factory([
232
		'name' => 'groups:user:invites',
233
		'text' => $text,
234
		'badge' => $invitation_count ?: null,
235
		'title' => $title,
236
		'href' => "groups/invitations/$user->username",
237
	]);
238
239
	return $return;
240
}
241
242
/**
243
 * Groups page handler
244
 *
245
 * URLs take the form of
246
 *  All groups:           groups/all
247
 *  User's owned groups:  groups/owner/<username>
248
 *  User's member groups: groups/member/<username>
249
 *  Group profile:        groups/profile/<guid>/<title>
250
 *  New group:            groups/add/<guid>
251
 *  Edit group:           groups/edit/<guid>
252
 *  Group invitations:    groups/invitations/<username>
253
 *  Invite to group:      groups/invite/<guid>
254
 *  Membership requests:  groups/requests/<guid>
255
 *  Group activity:       groups/activity/<guid>
256
 *  Group members:        groups/members/<guid>
257
 *
258
 * @param array $page Array of url segments for routing
259
 * @return bool
260
 */
261
function groups_page_handler($page) {
262
263
	if (!isset($page[0])) {
264
		$page[0] = 'all';
265
	}
266
267
	elgg_push_breadcrumb(elgg_echo('groups'), "groups/all");
268
269
	$vars = [];
270
	switch ($page[0]) {
271
		case 'all':
272
			// all groups doesn't get link to self
273
			elgg_pop_breadcrumb();
274
		case 'add':
275
		case 'owner':
276
		case 'search':
277
			echo elgg_view_resource("groups/{$page[0]}");
278
			break;
279
		case 'invitations':
280
		case 'member':
281
			echo elgg_view_resource("groups/{$page[0]}", [
282
				'username' => $page[1],
283
			]);
284
			break;
285
		case 'members':
286
			$vars['sort'] = elgg_extract('2', $page, 'alpha');
287
			$vars['guid'] = elgg_extract('1', $page);
288
			if (elgg_view_exists("resources/groups/members/{$vars['sort']}")) {
289
				echo elgg_view_resource("groups/members/{$vars['sort']}", $vars);
290
			} else {
291
				echo elgg_view_resource('groups/members', $vars);
292
			}
293
			break;
294
		case 'profile':
295
		case 'activity':
296
		case 'edit':
297
		case 'invite':
298
		case 'requests':
299
			echo elgg_view_resource("groups/{$page[0]}", [
300
				'guid' => $page[1],
301
			]);
302
			break;
303
		default:
304
			return false;
305
	}
306
	return true;
307
}
308
309
/**
310
 * Populates the ->getUrl() method for group objects
311
 *
312
 * @param string $hook   'entity:url'
313
 * @param string $type   'group'
314
 * @param string $url    current return value
315
 * @param array  $params supplied params
316
 *
317
 * @return void|string
318
 */
319
function groups_set_url($hook, $type, $url, $params) {
320
	
321
	$entity = elgg_extract('entity', $params);
322
	if (!$entity instanceof ElggGroup) {
323
		return;
324
	}
325
	
326
	$title = elgg_get_friendly_title($entity->getDisplayName());
327
	return "groups/profile/{$entity->guid}/$title";
328
}
329
330
/**
331
 * Add owner block link
332
 *
333
 * @param string         $hook   'register'
334
 * @param string         $type   'menu:owner_block'
335
 * @param ElggMenuItem[] $return current return value
336
 * @param array          $params supplied params
337
 *
338
 * @return void|ElggMenuItem[]
339
 */
340
function groups_activity_owner_block_menu($hook, $type, $return, $params) {
341
	
342
	$entity = elgg_extract('entity', $params);
343
	if (!$entity instanceof ElggGroup) {
344
		return;
345
	}
346
	
347
	if (!$entity->isToolEnabled('activity')) {
348
		return;
349
	}
350
	
351
	$url = "groups/activity/{$entity->guid}";
352
	$item = new ElggMenuItem('activity', elgg_echo('groups:activity'), $url);
353
	$return[] = $item;
354
	
355
	return $return;
356
}
357
358
/**
359
 * Returns a menu item for leaving a group
360
 *
361
 * @param \ElggGroup $group Group to leave
362
 * @param \ElggUser  $user  User to check leave action for
363
 *
364
 * @return \ElggMenuItem|false
365
 */
366
function groups_get_group_leave_menu_item(\ElggGroup $group, $user = null) {
367
	if (!$group instanceof \ElggGroup) {
368
		return false;
369
	}
370
	
371
	if (!$user instanceof ElggUser) {
372
		$user = elgg_get_logged_in_user_entity();
373
	}
374
	
375
	if (!$user instanceof ElggUser) {
376
		return false;
377
	}
378
	
379
	if (!$group->isMember($user) || ($group->owner_guid === $user->guid)) {
380
		// a member can leave a group if he/she doesn't own it
381
		return false;
382
	}
383
	
384
	return \ElggMenuItem::factory([
385
		'name' => 'groups:leave',
386
		'icon' => 'sign-out',
387
		'text' => elgg_echo('groups:leave'),
388
		'href' => elgg_http_add_url_query_elements('action/groups/leave', [
389
			'group_guid' => $group->guid,
390
			'user_guid' => $user->guid,
391
		]),
392
		'is_action' => true,
393
	]);
394
}
395
396
/**
397
 * Returns a menu item for joining a group
398
 *
399
 * @param \ElggGroup $group Group to leave
400
 * @param \ElggUser  $user  User to check leave action for
401
 *
402
 * @return \ElggMenuItem|false
403
 */
404
function groups_get_group_join_menu_item(\ElggGroup $group, $user = null) {
405
	if (!$group instanceof \ElggGroup) {
406
		return false;
407
	}
408
	
409
	if (!$user instanceof ElggUser) {
410
		$user = elgg_get_logged_in_user_entity();
411
	}
412
	
413
	if (!$user instanceof ElggUser) {
414
		return false;
415
	}
416
	
417
	if ($group->isMember($user)) {
418
		return false;
419
	}
420
	
421
	$menu_name = 'groups:joinrequest';
422
	if ($group->isPublicMembership() || $group->canEdit()) {
423
		// admins can always join
424
		// non-admins can join if membership is public
425
		$menu_name = 'groups:join';
426
	}
427
	
428
	return \ElggMenuItem::factory([
429
		'name' => $menu_name,
430
		'icon' => 'sign-in',
431
		'text' => elgg_echo($menu_name),
432
		'href' => elgg_http_add_url_query_elements('action/groups/join', [
433
			'group_guid' => $group->guid,
434
			'user_guid' => $user->guid,
435
		]),
436
		'is_action' => true,
437
	]);
438
}
439
440
/**
441
 * Add links/info to entity menu particular to group entities
442
 *
443
 * @param string         $hook   'register'
444
 * @param string         $type   'menu:entity'
445
 * @param ElggMenuItem[] $return current return value
446
 * @param array          $params supplied params
447
 *
448
 * @return void|ElggMenuItem[]
449
 */
450
function groups_entity_menu_setup($hook, $type, $return, $params) {
451 1
	$entity = elgg_extract('entity', $params);
452 1
	if (!($entity instanceof \ElggGroup)) {
453 1
		return;
454
	}
455
	
456 1
	$user = elgg_get_logged_in_user_entity();
457 1
	if (empty($user)) {
458 1
		return;
459
	}
460
	
461
	$group_join = groups_get_group_join_menu_item($entity, $user);
462
	if (!empty($group_join)) {
463
		$return[] = $group_join;
464
	}
465
	
466
	$group_leave = groups_get_group_leave_menu_item($entity, $user);
467
	if (!empty($group_leave)) {
468
		$return[] = $group_leave;
469
	}
470
		
471
	if ($user->isAdmin()) {
472
		$isFeatured = $entity->featured_group === "yes";
473
	
474
		$return[] = ElggMenuItem::factory([
475
			'name' => 'feature',
476
			'icon' => 'arrow-up',
477
			'text' => elgg_echo('groups:makefeatured'),
478
			'href' => "action/groups/featured?group_guid={$entity->guid}&action_type=feature",
479
			'is_action' => true,
480
			'item_class' => $isFeatured ? 'hidden' : '',
481
			'data-toggle' => 'unfeature',
482
		]);
483
	
484
		$return[] = ElggMenuItem::factory([
485
			'name' => 'unfeature',
486
			'icon' => 'arrow-down',
487
			'text' => elgg_echo('groups:makeunfeatured'),
488
			'href' => "action/groups/featured?group_guid={$entity->guid}&action_type=unfeature",
489
			'is_action' => true,
490
			'item_class' => $isFeatured ? '' : 'hidden',
491
			'data-toggle' => 'feature',
492
		]);
493
	}
494
	
495
	return $return;
496
}
497
498
/**
499
 * Add a remove user link to user hover menu when the page owner is a group
500
 *
501
 * @param string         $hook   'register'
502
 * @param string         $type   'menu:user_hover'
503
 * @param ElggMenuItem[] $return current return value
504
 * @param array          $params supplied params
505
 *
506
 * @return void|ElggMenuItem[]
507
 */
508
function groups_user_entity_menu_setup($hook, $type, $return, $params) {
509 1
	$group = elgg_get_page_owner_entity();
510
511 1
	if (!($group instanceof \ElggGroup) || !$group->canEdit()) {
512 1
		return;
513
	}
514
515
	$entity = elgg_extract('entity', $params);
516
517
	// Make sure we have a user and that user is a member of the group
518
	if (!($entity instanceof \ElggUser) || !$group->isMember($entity)) {
519
		return;
520
	}
521
522
	// Check if we are looking at the group owner
523
	if ($group->owner_guid === $entity->guid) {
524
		return;
525
	}
526
	
527
	$return[] = ElggMenuItem::factory([
528
		'name' => 'removeuser',
529
		'href' => "action/groups/remove?user_guid={$entity->guid}&group_guid={$group->guid}",
530
		'text' => elgg_echo('groups:removeuser'),
531
		'icon' => 'user-times',
532
		'confirm' => true,
533
		'priority' => 999,
534
	]);
535
536
	return $return;
537
}
538
539
/**
540
 * Groups created so create an access list for it
541
 *
542
 * @param string    $event  'create'
543
 * @param string    $type   'group'
544
 * @param ElggGroup $object the new group
545
 *
546
 * @return bool
547
 */
548
function groups_create_event_listener($event, $type, $object) {
549
550
	// ensure that user has sufficient permissions to update group metadata
551
	// prior to joining the group
552 13
	$ia = elgg_set_ignore_access(true);
553
554 13
	$ac_name = elgg_echo('groups:group') . ": " . $object->name;
555 13
	$ac_id = create_access_collection($ac_name, $object->guid, 'group_acl');
556
	
557 13
	elgg_set_ignore_access($ia);
558
559 13
	return (bool) $ac_id; // delete the group if acl creation fails
560
}
561
562
/**
563
 * Listen to group ownership changes and update group icon ownership
564
 * This will only move the source file, the actual icons are moved by
565
 * _elgg_filestore_move_icons()
566
 *
567
 * This operation is performed in an event listener to ensure that icons
568
 * are moved when ownership changes outside of the groups/edit action flow.
569
 *
570
 * @see _elgg_filestore_move_icons()
571
 *
572
 * @param string    $event "update:after"
573
 * @param string    $type  "group"
574
 * @param ElggGroup $group Group entity
575
 * @return void
576
 */
577
function groups_update_event_listener($event, $type, $group) {
578
579
	/* @var $group \ElggGroup */
580
581
	$original_attributes = $group->getOriginalAttributes();
582
583
	if (!empty($original_attributes['owner_guid'])) {
584
		$previous_owner_guid = $original_attributes['owner_guid'];
585
586
		// Update owned metadata
587
		$metadata = elgg_get_metadata([
588
			'guid' => $group->guid,
589
			'metadata_owner_guids' => $previous_owner_guid,
590
			'limit' => 0,
591
		]);
592
593
		if ($metadata) {
594
			foreach ($metadata as $md) {
595
				$md->owner_guid = $group->owner_guid;
596
				$md->save();
597
			}
598
		}
599
	}
600
601
	if (!empty($original_attributes['name'])) {
602
		// update access collection name if group name changes
603
		$group_name = html_entity_decode($group->name, ENT_QUOTES, 'UTF-8');
604
		$ac_name = elgg_echo('groups:group') . ": " . $group_name;
605
		$acl = _groups_get_group_acl($group);
606
		if ($acl) {
607
			$acl->name = $ac_name;
608
			$acl->save();
609
		}
610
	}
611
}
612
613
/**
614
 * Return the write access for the current group if the user has write access to it
615
 *
616
 * @param \Elgg\Hook $hook 'access:collection:write' 'all'
617
 * @return void|array
618
 */
619
function groups_write_acl_plugin_hook(\Elgg\Hook $hook) {
620
621 5
	$user_guid = $hook->getParam('user_id');
622 5
	$user = get_user($user_guid);
623 5
	if (!$user) {
624
		return;
625
	}
626
627 5
	$page_owner = elgg_get_page_owner_entity();
628 5
	if (!$page_owner instanceof ElggGroup) {
629 4
		return;
630
	}
631
632 1
	if (!$page_owner->canWriteToContainer($user_guid)) {
633 1
		return;
634
	}
635
636 1
	$allowed_access = [ACCESS_PRIVATE];
637 1
	$acl = _groups_get_group_acl($page_owner);
638 1
	if ($acl) {
639 1
		$allowed_access[] = $acl->id;
640
	}
641
642 1
	if ($page_owner->getContentAccessMode() !== ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
643 1
		$allowed_access[] = ACCESS_LOGGED_IN;
644 1
		if (!elgg_get_config('walled_garden')) {
645 1
			$allowed_access[] = ACCESS_PUBLIC;
646
		}
647
	}
648
649 1
	$write_acls = $hook->getValue();
650
651
	// add write access to the group
652 1
	if ($acl) {
653 1
		$write_acls[$acl->id] = $acl->getDisplayName();
654
	}
655
656 1
	foreach (array_keys($write_acls) as $access_id) {
657 1
		if (!in_array($access_id, $allowed_access)) {
658 1
			unset($write_acls[$access_id]);
659
		}
660
	}
661
662 1
	return $write_acls;
663
}
664
665
/**
666
 * Return the write access for the current group if the user has write access to it
667
 *
668
 * @param \Elgg\Hook $hook 'access_collection:display_name' 'access_collection'
669
 * @return void|string
670
 */
671
function groups_set_access_collection_name(\Elgg\Hook $hook) {
672
673 4
	$access_collection = $hook->getParam('access_collection');
674 4
	if (!$access_collection instanceof ElggAccessCollection) {
675
		return;
676
	}
677
678 4
	$owner = $access_collection->getOwnerEntity();
679 4
	if (!$owner instanceof ElggGroup) {
680 4
		return;
681
	}
682
	
683 1
	$page_owner = elgg_get_page_owner_entity();
684
685 1
	if ($page_owner && $page_owner->guid == $owner->guid) {
686 1
		return elgg_echo('groups:acl:in_context');
687
	}
688
689
	if ($owner->canWriteToContainer()) {
690
		return elgg_echo('groups:acl', [$owner->getDisplayName()]);
691
	}
692
}
693
694
/**
695
 * Perform actions when a user joins a group
696
 *
697
 * @param string $event       'join'
698
 * @param string $object_type 'group'
699
 * @param array  $params      supplied params
700
 *
701
 * @return void
702
 */
703
function groups_user_join_event_listener($event, $object_type, $params) {
704 8
	$group = elgg_extract('group', $params);
705 8
	$user = elgg_extract('user', $params);
706 8
	if (!$group instanceof ElggGroup || !$user instanceof ElggUser) {
707
		return;
708
	}
709
	
710
	// Remove any invite or join request flags
711 8
	remove_entity_relationship($group->guid, 'invited', $user->guid);
712 8
	remove_entity_relationship($user->guid, 'membership_request', $group->guid);
713
714 8
	if (elgg_extract('create_river_item', $params)) {
715
		elgg_create_river_item([
716
			'action_type' => 'join',
717
			'subject_guid' => $user->guid,
718
			'object_guid' => $group->guid,
719
		]);
720
	}
721
	
722
	// add a user to the group's access control
723 8
	$collection = _groups_get_group_acl($group);
724 8
	if (!empty($collection)) {
725 8
		$collection->addMember($user->guid);
726
	}
727 8
}
728
729
/**
730
 * Perform actions when a user leaves a group
731
 *
732
 * @param string $event       'leave'
733
 * @param string $object_type 'group'
734
 * @param array  $params      supplied params
735
 *
736
 * @return void
737
 */
738
function groups_user_leave_event_listener($event, $object_type, $params) {
739 2
	$group = elgg_extract('group', $params);
740 2
	$user = elgg_extract('user', $params);
741 2
	if (!$group instanceof ElggGroup || !$user instanceof ElggUser) {
742
		return;
743
	}
744
	
745
	// Remove any invite or join request flags (for some edge cases)
746 2
	remove_entity_relationship($group->guid, 'invited', $user->guid);
747 2
	remove_entity_relationship($user->guid, 'membership_request', $group->guid);
748
	
749
	// Removes a user from the group's access control
750 2
	$collection = _groups_get_group_acl($group);
751 2
	if (!empty($collection)) {
752 2
		$collection->removeMember($user->guid);
753
	}
754 2
}
755
756
/**
757
 * The default access for members only content is this group only. This makes
758
 * for better display of access (can tell it is group only), but does not change
759
 * access to the content.
760
 *
761
 * @param string $hook   Hook name
762
 * @param string $type   Hook type
763
 * @param int    $access Current default access
764
 *
765
 * @return int|void
766
 */
767
function groups_access_default_override($hook, $type, $access) {
768 6
	$page_owner = elgg_get_page_owner_entity();
769 6
	if (!($page_owner instanceof ElggGroup)) {
770 6
		return;
771
	}
772
			
773
	if ($page_owner->getContentAccessMode() !== ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
774
		return;
775
	}
776
	
777
	$acl = _groups_get_group_acl($page_owner);
778
	if (empty($acl)) {
779
		return;
780
	}
781
	
782
	return $acl->id;
783
}
784
785
/**
786
 * Grabs groups by invitations
787
 * Have to override all access until there's a way override access to getter functions.
788
 *
789
 * @param int   $user_guid    The user's guid
790
 * @param bool  $return_guids Return guids rather than ElggGroup objects
791
 * @param array $options      Additional options
792
 *
793
 * @return mixed ElggGroups or guids depending on $return_guids, or count
794
 */
795
function groups_get_invited_groups($user_guid, $return_guids = false, $options = []) {
796
797
	$ia = elgg_set_ignore_access(true);
798
799
	$defaults = [
800
		'relationship' => 'invited',
801
		'relationship_guid' => (int) $user_guid,
802
		'inverse_relationship' => true,
803
		'limit' => 0,
804
	];
805
806
	$options = array_merge($defaults, $options);
807
	$groups = elgg_get_entities($options);
808
809
	elgg_set_ignore_access($ia);
810
811
	if ($return_guids) {
812
		$guids = [];
813
		foreach ($groups as $group) {
814
			$guids[] = $group->getGUID();
815
		}
816
817
		return $guids;
818
	}
819
820
	return $groups;
821
}
822
823
/**
824
 * Function to use on groups for access. It will house private, loggedin, public,
825
 * and the group itself. This is when you don't want other groups or access lists
826
 * in the access options available.
827
 *
828
 * @param ElggGroup $group the group
829
 *
830
 * @return array
831
 */
832
function group_access_options($group) {
833
834
	$access_array = [
835
		ACCESS_PRIVATE => elgg_echo('access:label:private'),
836
		ACCESS_LOGGED_IN => elgg_echo('access:label:logged_in'),
837
	];
838
839
	if (!elgg_get_config('walled_garden')) {
840
		$access_array[ACCESS_PUBLIC] = elgg_echo('access:label:public');
841
	}
842
843
	if (!$group instanceof ElggGroup) {
844
		return $access_array;
845
	}
846
	
847
	$collection = _groups_get_group_acl($group);
848
	if ($collection) {
849
		$access_array[$collection->id] = $collection->getDisplayName();
850
	}
851
	
852
	return $access_array;
853
}
854
855
/**
856
 * Parse ECML on group profiles
857
 *
858
 * @param string $hook         'get_views'
859
 * @param string $type         'ecml'
860
 * @param array  $return_value current return value
861
 * @param mixed  $params       supplied params
862
 *
863
 * @return array
864
 */
865
function groupprofile_ecml_views_hook($hook, $type, $return_value, $params) {
866
	$return_value['groups/groupprofile'] = elgg_echo('groups:ecml:groupprofile');
867
868
	return $return_value;
869
}
870
871
/**
872
 * Setup invitation request actions
873
 *
874
 * @param string $hook   "register"
875
 * @param string $type   "menu:invitationrequest"
876
 * @param array  $menu   Menu items
877
 * @param array  $params Hook params
878
 * @return array
879
 */
880
function groups_invitationrequest_menu_setup($hook, $type, $menu, $params) {
881
882
	$group = elgg_extract('entity', $params);
883
	$user = elgg_extract('user', $params);
884
885
	if (!$group instanceof \ElggGroup) {
886
		return $menu;
887
	}
888
889
	if (!$user instanceof \ElggUser || !$user->canEdit()) {
890
		return $menu;
891
	}
892
893
	$accept_url = elgg_http_add_url_query_elements('action/groups/join', [
894
		'user_guid' => $user->guid,
895
		'group_guid' => $group->guid,
896
	]);
897
898
	$menu[] = \ElggMenuItem::factory([
899
		'name' => 'accept',
900
		'href' => $accept_url,
901
		'is_action' => true,
902
		'text' => elgg_echo('accept'),
903
		'link_class' => 'elgg-button elgg-button-submit',
904
		'is_trusted' => true,
905
	]);
906
907
	$delete_url = elgg_http_add_url_query_elements('action/groups/killinvitation', [
908
		'user_guid' => $user->guid,
909
		'group_guid' => $group->guid,
910
	]);
911
912
	$menu[] = \ElggMenuItem::factory([
913
		'name' => 'delete',
914
		'href' => $delete_url,
915
		'is_action' => true,
916
		'confirm' => elgg_echo('groups:invite:remove:check'),
917
		'text' => elgg_echo('delete'),
918
		'link_class' => 'elgg-button elgg-button-delete mlm',
919
	]);
920
921
	return $menu;
922
}
923
924
/**
925
 * Setup group members tabs
926
 *
927
 * @param string         $hook   "register"
928
 * @param string         $type   "menu:groups_members"
929
 * @param ElggMenuItem[] $menu   Menu items
930
 * @param array          $params Hook params
931
 *
932
 * @return void|ElggMenuItem[]
933
 */
934
function groups_members_menu_setup($hook, $type, $menu, $params) {
935
936
	$entity = elgg_extract('entity', $params);
937
	if (empty($entity) || !($entity instanceof ElggGroup)) {
938
		return;
939
	}
940
941
	$menu[] = ElggMenuItem::factory([
942
		'name' => 'alpha',
943
		'text' => elgg_echo('sort:alpha'),
944
		'href' => "groups/members/{$entity->getGUID()}",
945
		'priority' => 100
946
	]);
947
948
	$menu[] = ElggMenuItem::factory([
949
		'name' => 'newest',
950
		'text' => elgg_echo('sort:newest'),
951
		'href' => "groups/members/{$entity->getGUID()}/newest",
952
		'priority' => 200
953
	]);
954
955
	return $menu;
956
}
957
958
/**
959
 * Registers optional group invites menu item to topbar
960
 *
961
 * @elgg_plugin_hook register menu:topbar
962
 *
963
 * @param \Elgg\Hook $hook hook
964
 *
965
 * @return void|ElggMenuItem[]
966
 *
967
 * @since 3.0
968
 *
969
 * @internal
970
 */
971
function _groups_topbar_menu_setup(\Elgg\Hook $hook) {
972
973 1
	$user = elgg_get_logged_in_user_entity();
974 1
	if (empty($user)) {
975 1
		return;
976
	}
977
	
978
	$count = groups_get_invited_groups($user->guid, false, ['count' => true]);
979
	if (empty($count)) {
980
		return;
981
	}
982
	
983
	$result = $hook->getValue();
984
	
985
	// Invitations
986
	$text = elgg_echo('groups:invitations');
987
	$title = elgg_echo('groups:invitations:pending', [$count]);
988
	
989
	$result[] = \ElggMenuItem::factory([
990
		'name' => 'groups:user:invites',
991
		'text' => $text,
992
		'badge' => $count,
993
		'title' => $title,
994
		'icon' => 'users',
995
		'parent_name' => 'account',
996
		'section' => 'alt',
997
		'href' => "groups/invitations/{$user->username}",
998
	]);
999
	
1000
	return $result;
1001
}
1002
1003
/**
1004
 * Registers title menu items for group
1005
 *
1006
 * @elgg_plugin_hook register menu:title
1007
 *
1008
 * @param \Elgg\Hook $hook Hook
1009
 * @return \ElggMenuItem[]
1010
 *
1011
 * @internal
1012
 */
1013
function _groups_title_menu(\Elgg\Hook $hook) {
1014 1
	$group = $hook->getEntityParam();
1015 1
	if (!$group instanceof ElggGroup) {
1016 1
		return;
1017
	}
1018
	
1019
	$user = elgg_get_logged_in_user_entity();
1020
	if (empty($user)) {
1021
		return;
1022
	}
1023
	
1024
	$result = $hook->getValue();
1025
	if ($group->canEdit()) {
1026
		// group owners can edit the group and invite new members
1027
		$result[] = \ElggMenuItem::factory([
1028
			'name' => 'groups:edit',
1029
			'href' => "groups/edit/{$group->guid}",
1030
			'text' => elgg_echo('groups:edit'),
1031
			'link_class' => 'elgg-button elgg-button-action',
1032
		]);
1033
		$result[] = \ElggMenuItem::factory([
1034
			'name' => 'groups:invite',
1035
			'href' => "groups/invite/{$group->guid}",
1036
			'text' => elgg_echo('groups:invite'),
1037
			'link_class' => 'elgg-button elgg-button-action',
1038
		]);
1039
	}
1040
	
1041
	if ($group->isMember($user)) {
1042
		$is_owner = ($group->owner_guid === $user->guid);
1043
		$result[] = ElggMenuItem::factory([
1044
			'name' => 'group-dropdown',
1045
			'href' => false,
1046
			'text' => elgg_echo($is_owner ? 'groups:button:owned' : 'groups:button:joined'),
1047
			'icon_alt' => 'angle-down',
1048
			'link_class' => 'elgg-button elgg-button-action-done',
1049
			'child_menu' => [
1050
				'display' => 'dropdown',
1051
			],
1052
		]);
1053
		
1054
		$leave_group = groups_get_group_leave_menu_item($group, $user);
1055
		if ($leave_group) {
1056
			$leave_group->setParentName('group-dropdown');
1057
			$result[] = $leave_group;
1058
		}
1059
	} else {
1060
		$join_group = groups_get_group_join_menu_item($group, $user);
1061
		if ($join_group) {
1062
			$join_group->setLinkClass('elgg-button elgg-button-action');
1063
			$result[] = $join_group;
1064
		}
1065
	}
1066
	
1067
	return $result;
1068
}
1069
1070
/**
1071
 * Helper handler to correctly resolve page owners on group routes
1072
 *
1073
 * @see default_page_owner_handler()
1074
 *
1075
 * @param string $hook   "page_owner"
1076
 * @param string $type   "system"
1077
 * @param int    $return Page owner guid
1078
 * @param array  $params Hook params
1079
 * @return int|void
1080
 */
1081
function groups_default_page_owner_handler($hook, $type, $return, $params) {
1082
1083
	if ($return) {
1084
		return;
1085
	}
1086
1087
	$segments = _elgg_services()->request->getUrlSegments();
1088
	$identifier = array_shift($segments);
1089
1090
	if ($identifier !== 'groups') {
1091
		return;
1092
	}
1093
1094
	$page = array_shift($segments);
1095
1096
	switch ($page) {
1097
		case 'add' :
1098
			$guid = array_shift($segments);
1099
			if (!$guid) {
1100
				$guid = elgg_get_logged_in_user_guid();
1101
			}
1102
			return $guid;
1103
1104
		case 'edit':
1105
		case 'profile' :
1106
		case 'activity' :
1107
		case 'invite' :
1108
		case 'requests' :
1109
		case 'members' :
1110
		case 'profile' :
1111
			$guid = array_shift($segments);
1112
			if (!$guid) {
1113
				return;
1114
			}
1115
			return $guid;
1116
1117
		case 'member' :
1118
		case 'owner' :
1119
		case 'invitations':
1120
			$username = array_shift($segments);
1121
			if ($username) {
1122
				$user = get_user_by_username($username);
1123
			} else {
1124
				$user = elgg_get_logged_in_user_entity();
1125
			}
1126
			if (!$user) {
1127
				return;
1128
			}
1129
			return $user->guid;
1130
	}
1131
}
1132
1133
/**
1134
 * Setup filter tabs on /groups/all page
1135
 *
1136
 * @param string         $hook   "register"
1137
 * @param string         $type   "menu:filter:groups/all"
1138
 * @param ElggMenuItem[] $return Menu
1139
 * @param array          $params Hook params
1140
 * @return ElggMenuItem[]
1141
 */
1142
function groups_setup_filter_tabs($hook, $type, $return, $params) {
1143
1144
	$filter_value = elgg_extract('filter_value', $params);
1145
1146
	$return[] = ElggMenuItem::factory([
1147
		'name' => 'newest',
1148
		'text' => elgg_echo('sort:newest'),
1149
		'href' => 'groups/all?filter=newest',
1150
		'priority' => 200,
1151
		'selected' => $filter_value == 'newest',
1152
	]);
1153
1154
	$return[] = ElggMenuItem::factory([
1155
		'name' => 'alpha',
1156
		'text' => elgg_echo('sort:alpha'),
1157
		'href' => 'groups/all?filter=alpha',
1158
		'priority' => 250,
1159
		'selected' => $filter_value == 'alpha',
1160
	]);
1161
1162
	$return[] = ElggMenuItem::factory([
1163
		'name' => 'popular',
1164
		'text' => elgg_echo('sort:popular'),
1165
		'href' => 'groups/all?filter=popular',
1166
		'priority' => 300,
1167
		'selected' => $filter_value == 'popular',
1168
	]);
1169
1170
	$return[] = ElggMenuItem::factory([
1171
		'name' => 'featured',