Completed
Push — master ( 1e7aef...bb9d78 )
by Jeroen
29:20 queued 28:59
created

groups_get_group_leave_menu_item()   B

Complexity

Conditions 6
Paths 7

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 7
nop 2
dl 0
loc 27
rs 8.439
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 13 and the first side effect is on line 1289.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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
	elgg_extend_view('object/elements/imprint/contents', 'groups/imprint/member_count');
16
	elgg_extend_view('object/elements/imprint/contents', 'groups/imprint/membership_type');
17
	
18
	// Set up the menu
19
	$item = new ElggMenuItem('groups', elgg_echo('groups'), 'groups/all');
20
	elgg_register_menu_item('site', $item);
21
22
	// Register a page handler, so we can have nice URLs
23
	elgg_register_page_handler('groups', 'groups_page_handler');
24
25
	// Register URL handlers for groups
26
	elgg_register_plugin_hook_handler('entity:url', 'group', 'groups_set_url');
27
	elgg_register_plugin_hook_handler('entity:icon:sizes', 'group', 'groups_set_icon_sizes');
28
29
	// add group activity tool option
30
	if (elgg_get_plugin_setting('allow_activity', 'groups') === 'yes') {
31
		add_group_tool_option('activity', elgg_echo('groups:enableactivity'), true);
32
		elgg_extend_view('groups/tool_latest', 'groups/profile/activity_module');
33
	}
34
35
	// add link to owner block
36
	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'groups_activity_owner_block_menu');
37
38
	// group entity menu
39
	elgg_register_plugin_hook_handler('register', 'menu:entity', 'groups_entity_menu_setup');
40
41
	// group user hover menu
42
	elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'groups_user_entity_menu_setup');
43
44
	// invitation request actions
45
	elgg_register_plugin_hook_handler('register', 'menu:invitationrequest', 'groups_invitationrequest_menu_setup');
46
47
	// group members tabs
48
	elgg_register_plugin_hook_handler('register', 'menu:groups_members', 'groups_members_menu_setup');
49
	
50
	// topbar menu
51
	elgg_register_plugin_hook_handler('register', 'menu:topbar', '_groups_topbar_menu_setup');
52
53
	//extend some views
54
	elgg_extend_view('elgg.css', 'groups/css');
55
56
	// Access permissions
57
	elgg_register_plugin_hook_handler('access:collections:write', 'all', 'groups_write_acl_plugin_hook', 600);
58
	elgg_register_plugin_hook_handler('default', 'access', 'groups_access_default_override');
59
	elgg_register_plugin_hook_handler('access_collection:name', 'access_collection', 'groups_set_access_collection_name');
60
61
	// allow ecml in profiles
62
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'groupprofile_ecml_views_hook');
63
64
	// Register a handler for create groups
65
	elgg_register_event_handler('create', 'group', 'groups_create_event_listener');
66
	elgg_register_event_handler('update:after', 'group', 'groups_update_event_listener');
67
68
	elgg_register_event_handler('join', 'group', 'groups_user_join_event_listener');
69
	elgg_register_event_handler('leave', 'group', 'groups_user_leave_event_listener');
70
71
	// allow to be liked
72
	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
	elgg_register_plugin_hook_handler('page_owner', 'system', 'groups_default_page_owner_handler', 400);
77
78
	// Setup filter tabs on /groups/all page
79
	elgg_register_plugin_hook_handler('register', 'menu:filter:groups/all', 'groups_setup_filter_tabs');
80
81
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu_group_profile');
82
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu');
83
	elgg_register_plugin_hook_handler('register', 'menu:title', '_groups_title_menu');
84
}
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
		'description' => 'longtext',
100
		'briefdescription' => 'text',
101
		'interests' => 'tags',
102
	];
103
104
	$profile_defaults = elgg_trigger_plugin_hook('profile:fields', 'group', null, $profile_defaults);
105
106
	elgg_set_config('group', $profile_defaults);
107
108
	// register any tag metadata names
109
	foreach ($profile_defaults as $name => $type) {
110
		if ($type == 'tags') {
111
			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
			add_translation(get_current_language(), ["tag_names:$name" => elgg_echo("groups:$name")]);
116
		}
117
	}
118
}
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
	if (!elgg_in_context('group_profile') || !elgg_is_logged_in()) {
136
		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
	if (elgg_get_context() !== 'groups') {
190
		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':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
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 View Code Duplication
function groups_set_url($hook, $type, $url, $params) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
function groups_activity_owner_block_menu($hook, $type, $return, $params) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
	$entity = elgg_extract('entity', $params);
452
	if (!($entity instanceof \ElggGroup)) {
453
		return;
454
	}
455
	
456
	$user = elgg_get_logged_in_user_entity();
457
	if (empty($user)) {
458
		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
	$group = elgg_get_page_owner_entity();
510
511
	if (!($group instanceof \ElggGroup) || !$group->canEdit()) {
512
		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
	$ia = elgg_set_ignore_access(true);
553
554
	$ac_name = elgg_echo('groups:group') . ": " . $object->name;
555
	$ac_id = create_access_collection($ac_name, $object->guid, 'group_acl');
556
	
557
	elgg_set_ignore_access($ia);
558
559
	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
	$user_guid = $hook->getParam('user_id');
622
	$user = get_user($user_guid);
623
	if (!$user) {
624
		return;
625
	}
626
627
	$page_owner = elgg_get_page_owner_entity();
628
	if (!$page_owner instanceof ElggGroup) {
629
		return;
630
	}
631
632
	if (!$page_owner->canWriteToContainer($user_guid)) {
633
		return;
634
	}
635
636
	$allowed_access = [ACCESS_PRIVATE];
637
	$acl = _groups_get_group_acl($page_owner);
638
	if ($acl) {
639
		$allowed_access[] = $acl->id;
640
	}
641
642
	if ($page_owner->getContentAccessMode() !== ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
643
		$allowed_access[] = ACCESS_LOGGED_IN;
644
		if (!elgg_get_config('walled_garden')) {
645
			$allowed_access[] = ACCESS_PUBLIC;
646
		}
647
	}
648
649
	$write_acls = $hook->getValue();
650
651
	// add write access to the group
652
	if ($acl) {
653
		$write_acls[$acl->id] = $acl->getDisplayName();
654
	}
655
656
	foreach (array_keys($write_acls) as $access_id) {
657
		if (!in_array($access_id, $allowed_access)) {
658
			unset($write_acls[$access_id]);
659
		}
660
	}
661
662
	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
	$access_collection = $hook->getParam('access_collection');
674
	if (!$access_collection instanceof ElggAccessCollection) {
675
		return;
676
	}
677
678
	$owner = $access_collection->getOwnerEntity();
679
	if (!$owner instanceof ElggGroup) {
680
		return;
681
	}
682
	
683
	$page_owner = elgg_get_page_owner_entity();
684
685
	if ($page_owner && $page_owner->guid == $owner->guid) {
686
		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
	$group = elgg_extract('group', $params);
705
	$user = elgg_extract('user', $params);
706
	if (!$group instanceof ElggGroup || !$user instanceof ElggUser) {
707
		return;
708
	}
709
	
710
	// Remove any invite or join request flags
711
	remove_entity_relationship($group->guid, 'invited', $user->guid);
712
	remove_entity_relationship($user->guid, 'membership_request', $group->guid);
713
714
	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
	$collection = _groups_get_group_acl($group);
724
	if (!empty($collection)) {
725
		$collection->addMember($user->guid);
726
	}
727
}
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
	$group = elgg_extract('group', $params);
740
	$user = elgg_extract('user', $params);
741
	if (!$group instanceof ElggGroup || !$user instanceof ElggUser) {
742
		return;
743
	}
744
	
745
	// Remove any invite or join request flags (for some edge cases)
746
	remove_entity_relationship($group->guid, 'invited', $user->guid);
747
	remove_entity_relationship($user->guid, 'membership_request', $group->guid);
748
	
749
	// Removes a user from the group's access control
750
	$collection = _groups_get_group_acl($group);
751
	if (!empty($collection)) {
752
		$collection->removeMember($user->guid);
753
	}
754
}
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
	$page_owner = elgg_get_page_owner_entity();
769
	if (!($page_owner instanceof ElggGroup)) {
770
		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
	$user = elgg_get_logged_in_user_entity();
974
	if (empty($user)) {
975
		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
	$group = $hook->getEntityParam();
1015
	if (!$group instanceof ElggGroup) {
1016
		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',
1172
		'text' => elgg_echo('groups:featured'),
1173
		'href' => 'groups/all?filter=featured',
1174
		'priority' => 400,
1175
		'selected' => $filter_value == 'featured',
1176
	]);
1177
	
1178
	return $return;
1179
}
1180
1181
/**
1182
 * Add 'original' to group icon sizes
1183
 *
1184
 * @elgg_plugin_hook entity:icon:sizes group
1185
 *
1186
 * @param \Elgg\Hook $hook Hook
1187
 * @return array
1188
 */
1189
function groups_set_icon_sizes(\Elgg\Hook $hook) {
1190
1191
	$sizes = $hook->getValue();
1192
	$sizes['original'] = [];
1193
1194
	return $sizes;
1195
}
1196
1197
/**
1198
 * Get the access collection for a given group
1199
 *
1200
 * @param \ElggGroup $group the group
1201
 *
1202
 * @return \ElggAccessCollection|false
1203
 *
1204
 * @internal
1205
 * @since 3.0
1206
 */
1207
function _groups_get_group_acl(\ElggGroup $group) {
1208
	if (!$group instanceof \ElggGroup) {
1209
		return false;
1210
	}
1211
	
1212
	return elgg_extract(0, $group->getOwnedAccessCollections(['subtype' => 'group_acl']), false);
1213
}
1214
1215
/**
1216
 * Prepares variables for the group edit form view.
1217
 *
1218
 * @param mixed $group ElggGroup or null. If a group, uses values from the group.
1219
 * @return array
1220
 */
1221
function groups_prepare_form_vars($group = null) {
1222
	$values = [
1223
		'name' => '',
1224
		'membership' => ACCESS_PUBLIC,
1225
		'vis' => ACCESS_PUBLIC,
1226
		'guid' => null,
1227
		'entity' => null,
1228
		'owner_guid' => elgg_get_logged_in_user_guid(),
1229
		'content_access_mode' => ElggGroup::CONTENT_ACCESS_MODE_UNRESTRICTED
1230
	];
1231
1232
	// handle customizable profile fields
1233
	$fields = elgg_get_config('group');
1234
1235
	if ($fields) {
1236
		foreach ($fields as $name => $type) {
1237
			$values[$name] = '';
1238
		}
1239
	}
1240
1241
	// get current group settings
1242
	if ($group) {
1243
		foreach (array_keys($values) as $field) {
1244
			if (isset($group->$field)) {
1245
				$values[$field] = $group->$field;
1246
			}
1247
		}
1248
1249
		if ($group->access_id != ACCESS_PUBLIC && $group->access_id != ACCESS_LOGGED_IN) {
1250
			// group only access - this is done to handle access not created when group is created
1251
			$values['vis'] = ACCESS_PRIVATE;
1252
		} else {
1253
			$values['vis'] = $group->access_id;
1254
		}
1255
1256
		// The content_access_mode was introduced in 1.9. This method must be
1257
		// used for backwards compatibility with groups created before 1.9.
1258
		$values['content_access_mode'] = $group->getContentAccessMode();
1259
1260
		$values['entity'] = $group;
1261
	}
1262
1263
	// handle tool options
1264
	$entity = ($group instanceof \ElggGroup) ? $group : null;
1265
	$tools = elgg_get_group_tool_options($entity);
1266
	foreach ($tools as $group_option) {
1267
		$option_name = $group_option->name . "_enable";
1268
1269
		$enabled = $group_option->default_on;
1270
		if ($entity) {
1271
			$enabled = $entity->isToolEnabled($group_option->name);
1272
		}
1273
		$values[$option_name] = $enabled ? 'yes' : 'no';
1274
	}
1275
1276
	// get any sticky form settings
1277 View Code Duplication
	if (elgg_is_sticky_form('groups')) {
1278
		$sticky_values = elgg_get_sticky_values('groups');
1279
		foreach ($sticky_values as $key => $value) {
1280
			$values[$key] = $value;
1281
		}
1282
	}
1283
1284
	elgg_clear_sticky_form('groups');
1285
1286
	return $values;
1287
}
1288
1289
return function() {
1290
	elgg_register_event_handler('init', 'system', 'groups_init');
1291
1292
	// Ensure this runs after other plugins
1293
	elgg_register_event_handler('init', 'system', 'groups_fields_setup', 10000);
1294
};