Completed
Push — 3.0 ( 80deee...572da2 )
by Jeroen
99:03 queued 39:21
created

mod/groups/start.php (1 issue)

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