Completed
Push — master ( 886bfb...ddbe0a )
by Jeroen
65:58
created

_groups_gatekeeper_allow_profile_page()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

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