Completed
Push — master ( 0ffdca...fb72ff )
by Jeroen
15:02
created

mod/groups/start.php (2 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
/**
3
 * Elgg groups plugin
4
 *
5
 * @package ElggGroups
6
 */
7
8
elgg_register_event_handler('init', 'system', 'groups_init');
9
10
// Ensure this runs after other plugins
11
elgg_register_event_handler('init', 'system', 'groups_fields_setup', 10000);
12
13
/**
14
 * Initialize the groups plugin.
15
 */
16
function groups_init() {
17
18
	elgg_register_library('elgg:groups', __DIR__ . '/lib/groups.php');
19
	elgg_load_library('elgg:groups');
20
	
21
	// register group entities for search
22
	elgg_register_entity_type('group', '');
23
24
	// Set up the menu
25
	$item = new ElggMenuItem('groups', elgg_echo('groups'), 'groups/all');
26
	elgg_register_menu_item('site', $item);
27
28
	// Register a page handler, so we can have nice URLs
29
	elgg_register_page_handler('groups', 'groups_page_handler');
30
31
	// Register URL handlers for groups
32
	elgg_register_plugin_hook_handler('entity:url', 'group', 'groups_set_url');
33
	elgg_register_plugin_hook_handler('entity:icon:sizes', 'group', 'groups_set_icon_sizes');
34
35
	// add group activity tool option
36
	if (elgg_get_plugin_setting('allow_activity', 'groups') === 'yes') {
37
		add_group_tool_option('activity', elgg_echo('groups:enableactivity'), true);
38
		elgg_extend_view('groups/tool_latest', 'groups/profile/activity_module');
39
	}
40
41
	// add link to owner block
42
	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'groups_activity_owner_block_menu');
43
44
	// group entity menu
45
	elgg_register_plugin_hook_handler('register', 'menu:entity', 'groups_entity_menu_setup');
46
47
	// group user hover menu
48
	elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'groups_user_entity_menu_setup');
49
50
	// invitation request actions
51
	elgg_register_plugin_hook_handler('register', 'menu:invitationrequest', 'groups_invitationrequest_menu_setup');
52
53
	// group members tabs
54
	elgg_register_plugin_hook_handler('register', 'menu:groups_members', 'groups_members_menu_setup');
55
56
	//extend some views
57
	elgg_extend_view('elgg.css', 'groups/css');
58
	if (_elgg_view_may_be_altered('groups/js', __DIR__ . '/views/default/groups/js.php')) {
59
		elgg_deprecated_notice('groups/js view has been deprecated. Use AMD modules instead', '2.2');
60
		elgg_extend_view('elgg.js', 'groups/js');
61
	}
62
63
	// Access permissions
64
	elgg_register_plugin_hook_handler('access:collections:write', 'all', 'groups_write_acl_plugin_hook', 600);
65
	elgg_register_plugin_hook_handler('default', 'access', 'groups_access_default_override');
66
67
	// Register profile menu hook
68
	elgg_register_plugin_hook_handler('profile_menu', 'profile', 'activity_profile_menu');
69
70
	// allow ecml in profiles
71
	elgg_register_plugin_hook_handler('get_views', 'ecml', 'groupprofile_ecml_views_hook');
72
73
	// Register a handler for create groups
74
	elgg_register_event_handler('create', 'group', 'groups_create_event_listener');
75
	elgg_register_event_handler('update:after', 'group', 'groups_update_event_listener');
76
77
	elgg_register_event_handler('join', 'group', 'groups_user_join_event_listener');
78
	elgg_register_event_handler('leave', 'group', 'groups_user_leave_event_listener');
79
80
	elgg_register_plugin_hook_handler('access:collections:add_user', 'collection', 'groups_access_collection_override');
81
82
	elgg_register_event_handler('upgrade', 'system', 'groups_run_upgrades');
83
84
	// Add tests
85
	elgg_register_plugin_hook_handler('unit_test', 'system', 'groups_test');
86
87
	// allow to be liked
88
	elgg_register_plugin_hook_handler('likes:is_likable', 'group:', 'Elgg\Values::getTrue');
89
90
	// prepare profile buttons to be registered in the title menu
91
	elgg_register_plugin_hook_handler('profile_buttons', 'group', 'groups_prepare_profile_buttons');
92
93
	// Help core resolve page owner guids from group routes
94
	// Registered with an earlier priority to be called before default_page_owner_handler()
95
	elgg_register_plugin_hook_handler('page_owner', 'system', 'groups_default_page_owner_handler', 400);
96
97
	// Setup filter tabs on /groups/all page
98
	elgg_register_plugin_hook_handler('register', 'menu:filter:groups/all', 'groups_setup_filter_tabs');
99
100
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu_group_profile');
101
	elgg_register_plugin_hook_handler('register', 'menu:page', '_groups_page_menu');
102
}
103
104
/**
105
 * This function loads a set of default fields into the profile, then triggers
106
 * a hook letting other plugins to edit add and delete fields.
107
 *
108
 * Note: This is a system:init event triggered function and is run at a super
109
 * low priority to guarantee that it is called after all other plugins have
110
 * initialized.
111
 */
112
function groups_fields_setup() {
113
114
	$profile_defaults = array(
115
		'description' => 'longtext',
116
		'briefdescription' => 'text',
117
		'interests' => 'tags',
118
		//'website' => 'url',
119
	);
120
121
	$profile_defaults = elgg_trigger_plugin_hook('profile:fields', 'group', NULL, $profile_defaults);
122
123
	elgg_set_config('group', $profile_defaults);
124
125
	// register any tag metadata names
126
	foreach ($profile_defaults as $name => $type) {
127
		if ($type == 'tags') {
128
			elgg_register_tag_metadata_name($name);
129
130
			// only shows up in search but why not just set this in en.php as doing it here
131
			// means you cannot override it in a plugin
132
			add_translation(get_current_language(), array("tag_names:$name" => elgg_echo("groups:$name")));
133
		}
134
	}
135
}
136
137
/**
138
 * Register menu items for the page menu
139
 *
140
 * @param string $hook
141
 * @param string $type
142
 * @param array  $return
143
 * @param array  $params
144
 * @return array
145
 *
146
 * @access private
147
 *
148
 * @since 3.0
149
 */
150
function _groups_page_menu_group_profile($hook, $type, $return, $params) {
151
	
152
	if (!elgg_in_context('group_profile') || !elgg_is_logged_in()) {
153
		return;
154
	}
155
	
156
	// Get the page owner entity
157
	$page_owner = elgg_get_page_owner_entity();
158
	if (!($page_owner instanceof ElggGroup)) {
159
		return;
160
	}
161
	
162
	if (!$page_owner->canEdit() || $page_owner->isPublicMembership()) {
163
		return;
164
	}
165
	
166
	$count = elgg_get_entities_from_relationship(array(
167
		'type' => 'user',
168
		'relationship' => 'membership_request',
169
		'relationship_guid' => $page_owner->guid,
170
		'inverse_relationship' => true,
171
		'count' => true,
172
	));
173
174
	$text = elgg_echo('groups:membershiprequests');
175
	$title = $text;
176
	if ($count) {
177
		$title = elgg_echo('groups:membershiprequests:pending', array($count));
178
	}
179
	
180
	$return[] = \ElggMenuItem::factory([
181
		'name' => 'membership_requests',
182
		'text' => $text,
183
		'badge' => $count ? $count : null,
184
		'title' => $title,
185
		'href' => "groups/requests/{$page_owner->guid}",
186
	]);
187
	
188
	return $return;
189
}
190
191
/**
192
 * Register menu items for the page menu
193
 *
194
 * @param string $hook
195
 * @param string $type
196
 * @param array  $return
197
 * @param array  $params
198
 * @return array
199
 *
200
 * @access private
201
 *
202
 * @since 3.0
203
 */
204
function _groups_page_menu($hook, $type, $return, $params) {
205
	
206
	if (elgg_get_context() !== 'groups') {
207
		return;
208
	}
209
	
210
	// Get the page owner entity
211
	$page_owner = elgg_get_page_owner_entity();
212
	if ($page_owner instanceof ElggGroup) {
213
		return;
214
	}
215
	
216
	$return[] = \ElggMenuItem::factory([
217
		'name' => 'groups:all',
218
		'text' => elgg_echo('groups:all'),
219
		'href' => 'groups/all',
220
	]);
221
222
	$user = elgg_get_logged_in_user_entity();
223
	if (!$user) {
224
		return $return;
225
	}
226
	
227
	$return[] = \ElggMenuItem::factory([
228
		'name' => 'groups:owned',
229
		'text' => elgg_echo('groups:owned'),
230
		'href' => "groups/owner/$user->username",
231
	]);
232
	
233
	$return[] = \ElggMenuItem::factory([
234
		'name' => 'groups:member',
235
		'text' => elgg_echo('groups:yours'),
236
		'href' => "groups/member/$user->username",
237
	]);
238
239
	$invitation_count = groups_get_invited_groups($user->guid, false, ['count' => true]);
240
241
	// Invitations
242
	$text = elgg_echo('groups:invitations');
243
	$title = $text;
244
	if ($invitation_count) {
245
		$title = elgg_echo('groups:invitations:pending', array($invitation_count));
246
	}
247
248
	$return[] = \ElggMenuItem::factory([
249
		'name' => 'groups:user:invites',
250
		'text' => $text,
251
		'badge' => $invitation_count ? $invitation_count : null,
252
		'title' => $title,
253
		'href' => "groups/invitations/$user->username",
254
	]);
255
256
	return $return;
257
}
258
259
/**
260
 * Groups page handler
261
 *
262
 * URLs take the form of
263
 *  All groups:           groups/all
264
 *  User's owned groups:  groups/owner/<username>
265
 *  User's member groups: groups/member/<username>
266
 *  Group profile:        groups/profile/<guid>/<title>
267
 *  New group:            groups/add/<guid>
268
 *  Edit group:           groups/edit/<guid>
269
 *  Group invitations:    groups/invitations/<username>
270
 *  Invite to group:      groups/invite/<guid>
271
 *  Membership requests:  groups/requests/<guid>
272
 *  Group activity:       groups/activity/<guid>
273
 *  Group members:        groups/members/<guid>
274
 *
275
 * @param array $page Array of url segments for routing
276
 * @return bool
277
 */
278
function groups_page_handler($page) {
279
280
	if (!isset($page[0])) {
281
		$page[0] = 'all';
282
	}
283
284
	elgg_push_breadcrumb(elgg_echo('groups'), "groups/all");
285
286
	$vars = [];
287
	switch ($page[0]) {
288
		case 'add':
289
		case 'all':
290
		case 'owner':
291
		case 'search':
292
			echo elgg_view_resource("groups/{$page[0]}");
293
			break;
294
		case 'invitations':
295
		case 'member':
296
			echo elgg_view_resource("groups/{$page[0]}", [
297
				'username' => $page[1],
298
			]);
299
			break;
300
		case 'members':
301
			$vars['sort'] = elgg_extract('2', $page, 'alpha');
302
			$vars['guid'] = elgg_extract('1', $page);
303
			if (elgg_view_exists("resources/groups/members/{$vars['sort']}")) {
304
				echo elgg_view_resource("groups/members/{$vars['sort']}", $vars);
305
			} else {
306
				echo elgg_view_resource('groups/members', $vars);
307
			}
308
			break;
309
		case 'profile':
310
		case 'activity':
311
		case 'edit':
312
		case 'invite':
313
		case 'requests':
314
			echo elgg_view_resource("groups/{$page[0]}", [
315
				'guid' => $page[1],
316
			]);
317
			break;
318
		default:
319
			return false;
320
	}
321
	return true;
322
}
323
324
/**
325
 * Populates the ->getUrl() method for group objects
326
 *
327
 * @param string $hook
328
 * @param string $type
329
 * @param string $url
330
 * @param array  $params
331
 * @return string
332
 */
333
function groups_set_url($hook, $type, $url, $params) {
334
	$entity = $params['entity'];
335
	$title = elgg_get_friendly_title($entity->name);
336
	return "groups/profile/{$entity->guid}/$title";
337
}
338
339
/**
340
 * Add owner block link
341
 */
342
function groups_activity_owner_block_menu($hook, $type, $return, $params) {
343
	if (elgg_instanceof($params['entity'], 'group')) {
344
		if ($params['entity']->activity_enable != "no") {
345
			$url = "groups/activity/{$params['entity']->guid}";
346
			$item = new ElggMenuItem('activity', elgg_echo('groups:activity'), $url);
347
			$return[] = $item;
348
		}
349
	}
350
351
	return $return;
352
}
353
354
/**
355
 * Add links/info to entity menu particular to group entities
356
 */
357
function groups_entity_menu_setup($hook, $type, $return, $params) {
358
	if (elgg_in_context('widgets')) {
359
		return $return;
360
	}
361
362
	/* @var ElggGroup $entity */
363
	$entity = $params['entity'];
364
	$handler = elgg_extract('handler', $params, false);
365
	if ($handler != 'groups') {
366
		return $return;
367
	}
368
369
	/* @var ElggMenuItem $item */
370
	foreach ($return as $index => $item) {
371
		if (in_array($item->getName(), array('access', 'likes', 'unlike', 'edit', 'delete'))) {
372
			unset($return[$index]);
373
		}
374
	}
375
376
	// membership type
377
	if ($entity->isPublicMembership()) {
378
		$mem = elgg_echo("groups:open");
379
	} else {
380
		$mem = elgg_echo("groups:closed");
381
	}
382
383
	$options = array(
384
		'name' => 'membership',
385
		'text' => $mem,
386
		'href' => false,
387
		'priority' => 100,
388
	);
389
	$return[] = ElggMenuItem::factory($options);
390
391
	// number of members
392
	$num_members = $entity->getMembers(array('count' => true));
393
	$members_string = elgg_echo('groups:member');
394
	$options = array(
395
		'name' => 'members',
396
		'text' => $num_members . ' ' . $members_string,
397
		'href' => false,
398
		'priority' => 200,
399
	);
400
	$return[] = ElggMenuItem::factory($options);
401
402
	// feature link
403
	if (elgg_is_admin_logged_in()) {
404
		$isFeatured = $entity->featured_group == "yes";
405
406
		$return[] = ElggMenuItem::factory(array(
407
			'name' => 'feature',
408
			'text' => elgg_echo("groups:makefeatured"),
409
			'href' => elgg_add_action_tokens_to_url("action/groups/featured?group_guid={$entity->guid}&action_type=feature"),
410
			'priority' => 300,
411
			'item_class' => $isFeatured ? 'hidden' : '',
412
			'deps' => 'groups/navigation',
413
		));
414
415
		$return[] = ElggMenuItem::factory(array(
416
			'name' => 'unfeature',
417
			'text' => elgg_echo("groups:makeunfeatured"),
418
			'href' => elgg_add_action_tokens_to_url("action/groups/featured?group_guid={$entity->guid}&action_type=unfeature"),
419
			'priority' => 300,
420
			'item_class' => $isFeatured ? '' : 'hidden',
421
			'deps' => 'groups/navigation',
422
		));
423
	}
424
425
	return $return;
426
}
427
428
/**
429
 * Add a remove user link to user hover menu when the page owner is a group
430
 */
431
function groups_user_entity_menu_setup($hook, $type, $return, $params) {
432
	if (elgg_is_logged_in()) {
433
		$group = elgg_get_page_owner_entity();
434
435
		// Check for valid group
436
		if (!elgg_instanceof($group, 'group')) {
437
			return $return;
438
		}
439
440
		$entity = $params['entity'];
441
442
		// Make sure we have a user and that user is a member of the group
443
		if (!elgg_instanceof($entity, 'user') || !$group->isMember($entity)) {
444
			return $return;
445
		}
446
447
		// Add remove link if we can edit the group, and if we're not trying to remove the group owner
448
		if ($group->canEdit() && $group->getOwnerGUID() != $entity->guid) {
449
			$return[] = ElggMenuItem::factory([
450
				'name' => 'removeuser',
451
				'href' => "action/groups/remove?user_guid={$entity->guid}&group_guid={$group->guid}",
452
				'text' => elgg_echo('groups:removeuser'),
453
				'confirm' => true,
454
				'priority' => 999,
455
			]);
456
		}
457
	}
458
459
	return $return;
460
}
461
462
/**
463
 * Groups created so create an access list for it
464
 */
465
function groups_create_event_listener($event, $object_type, $object) {
466
	$ac_name = elgg_echo('groups:group') . ": " . $object->name;
467
	$ac_id = create_access_collection($ac_name, $object->guid);
468
	if ($ac_id) {
469
		$object->group_acl = $ac_id;
470
	} else {
471
		// delete group if access creation fails
472
		return false;
473
	}
474
475
	return true;
476
}
477
478
/**
479
 * Listen to group ownership changes and update group icon ownership
480
 * This will only move the source file, the actual icons are moved by
481
 * _elgg_filestore_move_icons()
482
 *
483
 * This operation is performed in an event listener to ensure that icons
484
 * are moved when ownership changes outside of the groups/edit action flow.
485
 *
486
 * @todo #4683 proposes that icons are owned by groups and not group owners
487
 * @see _elgg_filestore_move_icons()
488
 *
489
 * @param string    $event "update:after"
490
 * @param string    $type  "group"
491
 * @param ElggGroup $group Group entity
492
 * @return void
493
 */
494
function groups_update_event_listener($event, $type, $group) {
495
496
	/* @var $group \ElggGroup */
497
498
	$original_attributes = $group->getOriginalAttributes();
499
500
	if (!empty($original_attributes['owner_guid'])) {
501
		$previous_owner_guid = $original_attributes['owner_guid'];
502
503
		// Update owned metadata
504
		$metadata = elgg_get_metadata([
505
			'guid' => $group->guid,
506
			'metadata_owner_guids' => $previous_owner_guid,
507
			'limit' => 0,
508
		]);
509
510
		if ($metadata) {
511
			foreach ($metadata as $md) {
0 ignored issues
show
The expression $metadata of type array<integer,object<ElggExtender>>|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
512
				$md->owner_guid = $group->owner_guid;
513
				$md->save();
514
			}
515
		}
516
	}
517
518
	if (!empty($original_attributes['name'])) {
519
		// update access collection name if group name changes
520
		$group_name = html_entity_decode($group->name, ENT_QUOTES, 'UTF-8');
521
		$ac_name = elgg_echo('groups:group') . ": " . $group_name;
522
		$acl = get_access_collection($group->group_acl);
523
		if ($acl) {
524
			$acl->name = $ac_name;
525
			$acl->save();
0 ignored issues
show
The method save cannot be called on $acl (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
526
		}
527
	}
528
}
529
530
/**
531
 * Return the write access for the current group if the user has write access to it.
532
 */
533
function groups_write_acl_plugin_hook($hook, $entity_type, $returnvalue, $params) {
534
535
	$user_guid = sanitise_int(elgg_extract('user_id', $params), false);
536
	$user = get_user($user_guid);
537
	if (empty($user)) {
538
		return $returnvalue;
539
	}
540
541
	$page_owner = elgg_get_page_owner_entity();
542
	if (!($page_owner instanceof ElggGroup)) {
543
		return $returnvalue;
544
	}
545
546
	if (!$page_owner->canWriteToContainer($user_guid)) {
547
		return $returnvalue;
548
	}
549
550
	// check group content access rules
551
	$allowed_access = array(
552
		ACCESS_PRIVATE
553
	);
554
555
	if ($page_owner->getContentAccessMode() !== ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
556
		$allowed_access[] = ACCESS_LOGGED_IN;
557
		$allowed_access[] = ACCESS_PUBLIC;
558
	}
559
560
	foreach ($returnvalue as $access_id => $access_string) {
561
		if (!in_array($access_id, $allowed_access)) {
562
			unset($returnvalue[$access_id]);
563
		}
564
	}
565
566
	// add write access to the group
567
	$returnvalue[$page_owner->group_acl] = elgg_echo('groups:acl', array($page_owner->name));
568
569
	return $returnvalue;
570
}
571
572
/**
573
 * Listens to a group join event and adds a user to the group's access control
574
 *
575
 */
576
function groups_user_join_event_listener($event, $object_type, $object) {
577
578
	$group = $object['group'];
579
	$user = $object['user'];
580
	$acl = $group->group_acl;
581
582
	add_user_to_access_collection($user->guid, $acl);
583
584
	return true;
585
}
586
587
/**
588
 * Make sure users are added to the access collection
589
 */
590
function groups_access_collection_override($hook, $entity_type, $returnvalue, $params) {
591
	if (isset($params['collection'])) {
592
		if (elgg_instanceof(get_entity($params['collection']->owner_guid), 'group')) {
593
			return true;
594
		}
595
	}
596
}
597
598
/**
599
 * Listens to a group leave event and removes a user from the group's access control
600
 *
601
 */
602
function groups_user_leave_event_listener($event, $object_type, $object) {
603
604
	$group = $object['group'];
605
	$user = $object['user'];
606
	$acl = $group->group_acl;
607
608
	remove_user_from_access_collection($user->guid, $acl);
609
610
	return true;
611
}
612
613
/**
614
 * The default access for members only content is this group only. This makes
615
 * for better display of access (can tell it is group only), but does not change
616
 * access to the content.
617
 *
618
 * @param string $hook   Hook name
619
 * @param string $type   Hook type
620
 * @param int    $access Current default access
621
 * @return int
622
 */
623
function groups_access_default_override($hook, $type, $access) {
624
	$page_owner = elgg_get_page_owner_entity();
625
626
	if ($page_owner instanceof ElggGroup) {
627
		if ($page_owner->getContentAccessMode() == ElggGroup::CONTENT_ACCESS_MODE_MEMBERS_ONLY) {
628
			$access = $page_owner->group_acl;
629
		}
630
	}
631
632
	return $access;
633
}
634
635
/**
636
 * Grabs groups by invitations
637
 * Have to override all access until there's a way override access to getter functions.
638
 *
639
 * @param int   $user_guid    The user's guid
640
 * @param bool  $return_guids Return guids rather than ElggGroup objects
641
 * @param array $options      Additional options
642
 *
643
 * @return mixed ElggGroups or guids depending on $return_guids, or count
644
 */
645
function groups_get_invited_groups($user_guid, $return_guids = false, $options = array()) {
646
647
	$ia = elgg_set_ignore_access(true);
648
649
	$defaults = array(
650
		'relationship' => 'invited',
651
		'relationship_guid' => (int) $user_guid,
652
		'inverse_relationship' => true,
653
		'limit' => 0,
654
	);
655
656
	$options = array_merge($defaults, $options);
657
	$groups = elgg_get_entities_from_relationship($options);
658
659
	elgg_set_ignore_access($ia);
660
661
	if ($return_guids) {
662
		$guids = array();
663
		foreach ($groups as $group) {
664
			$guids[] = $group->getGUID();
665
		}
666
667
		return $guids;
668
	}
669
670
	return $groups;
671
}
672
673
/**
674
 * Join a user to a group, add river event, clean-up invitations
675
 *
676
 * @param ElggGroup $group
677
 * @param ElggUser  $user
678
 * @return bool
679
 */
680
function groups_join_group($group, $user) {
681
682
	// access ignore so user can be added to access collection of invisible group
683
	$ia = elgg_set_ignore_access(TRUE);
684
	$result = $group->join($user);
685
	elgg_set_ignore_access($ia);
686
687
	if ($result) {
688
		// flush user's access info so the collection is added
689
		get_access_list($user->guid, 0, true);
690
691
		// Remove any invite or join request flags
692
		remove_entity_relationship($group->guid, 'invited', $user->guid);
693
		remove_entity_relationship($user->guid, 'membership_request', $group->guid);
694
695
		elgg_create_river_item(array(
696
			'view' => 'river/relationship/member/create',
697
			'action_type' => 'join',
698
			'subject_guid' => $user->guid,
699
			'object_guid' => $group->guid,
700
		));
701
702
		return true;
703
	}
704
705
	return false;
706
}
707
708
/**
709
 * Function to use on groups for access. It will house private, loggedin, public,
710
 * and the group itself. This is when you don't want other groups or access lists
711
 * in the access options available.
712
 *
713
 * @return array
714
 */
715
function group_access_options($group) {
716
	$access_array = array(
717
		ACCESS_PRIVATE => 'private',
718
		ACCESS_LOGGED_IN => 'logged in users',
719
		ACCESS_PUBLIC => 'public',
720
		$group->group_acl => elgg_echo('groups:acl', array($group->name)),
721
	);
722
	return $access_array;
723
}
724
725
function activity_profile_menu($hook, $entity_type, $return_value, $params) {
726
727
	if (!$params['owner'] instanceof ElggGroup
728
			|| elgg_get_plugin_setting('allow_activity', 'groups') === 'no') {
729
		return;
730
	}
731
732
	$return_value[] = array(
733
		'text' => elgg_echo('groups:activity'),
734
		'href' => "groups/activity/{$params['owner']->guid}"
735
	);
736
	return $return_value;
737
}
738
739
/**
740
 * Parse ECML on group profiles
741
 */
742
function groupprofile_ecml_views_hook($hook, $entity_type, $return_value, $params) {
743
	$return_value['groups/groupprofile'] = elgg_echo('groups:ecml:groupprofile');
744
745
	return $return_value;
746
}
747
748
/**
749
 * Process upgrades for the groups plugin
750
 */
751
function groups_run_upgrades() {
752
	$path = __DIR__ . '/upgrades/';
753
	$files = elgg_get_upgrade_files($path);
754
	foreach ($files as $file) {
755
		include "$path{$file}";
756
	}
757
}
758
759
/**
760
 * Runs unit tests for groups
761
 *
762
 * @return array
763
 */
764
function groups_test($hook, $type, $value, $params) {
765
	$value[] = elgg_get_plugins_path() . 'groups/tests/write_access.php';
766
	return $value;
767
}
768
769
/**
770
 * Setup invitation request actions
771
 *
772
 * @param string $hook   "register"
773
 * @param string $type   "menu:invitationrequest"
774
 * @param array  $menu   Menu items
775
 * @param array  $params Hook params
776
 * @return array
777
 */
778
function groups_invitationrequest_menu_setup($hook, $type, $menu, $params) {
779
780
	$group = elgg_extract('entity', $params);
781
	$user = elgg_extract('user', $params);
782
783
	if (!$group instanceof \ElggGroup) {
784
		return $menu;
785
	}
786
787
	if (!$user instanceof \ElggUser || !$user->canEdit()) {
788
		return $menu;
789
	}
790
791
	$accept_url = elgg_http_add_url_query_elements('action/groups/join', array(
792
		'user_guid' => $user->guid,
793
		'group_guid' => $group->guid,
794
	));
795
796
	$menu[] = \ElggMenuItem::factory(array(
797
		'name' => 'accept',
798
		'href' => $accept_url,
799
		'is_action' => true,
800
		'text' => elgg_echo('accept'),
801
		'link_class' => 'elgg-button elgg-button-submit',
802
		'is_trusted' => true,
803
	));
804
805
	$delete_url = elgg_http_add_url_query_elements('action/groups/killinvitation', array(
806
		'user_guid' => $user->guid,
807
		'group_guid' => $group->guid,
808
	));
809
810
	$menu[] = \ElggMenuItem::factory(array(
811
		'name' => 'delete',
812
		'href' => $delete_url,
813
		'is_action' => true,
814
		'confirm' => elgg_echo('groups:invite:remove:check'),
815
		'text' => elgg_echo('delete'),
816
		'link_class' => 'elgg-button elgg-button-delete mlm',
817
	));
818
819
	return $menu;
820
}
821
822
/**
823
 * Setup group members tabs
824
 *
825
 * @param string         $hook   "register"
826
 * @param string         $type   "menu:groups_members"
827
 * @param ElggMenuItem[] $menu   Menu items
828
 * @param array          $params Hook params
829
 *
830
 * @return void|ElggMenuItem[]
831
 */
832
function groups_members_menu_setup($hook, $type, $menu, $params) {
833
834
	$entity = elgg_extract('entity', $params);
835
	if (empty($entity) || !($entity instanceof ElggGroup)) {
836
		return;
837
	}
838
839
	$menu[] = ElggMenuItem::factory([
840
		'name' => 'alpha',
841
		'text' => elgg_echo('sort:alpha'),
842
		'href' => "groups/members/{$entity->getGUID()}",
843
		'priority' => 100
844
	]);
845
846
	$menu[] = ElggMenuItem::factory([
847
		'name' => 'newest',
848
		'text' => elgg_echo('sort:newest'),
849
		'href' => "groups/members/{$entity->getGUID()}/newest",
850
		'priority' => 200
851
	]);
852
853
	return $menu;
854
}
855
856
/**
857
 * Returns menu items to be registered in the title menu of the group profile
858
 *
859
 * @param string         $hook   "profile_buttons"
860
 * @param string         $type   "group"
861
 * @param ElggMenuItem[] $items  Buttons
862
 * @param array          $params Hook params
863
 * @return ElggMenuItem[]
864
 */
865
function groups_prepare_profile_buttons($hook, $type, $items, $params) {
866
867
	$group = elgg_extract('entity', $params);
868
	if (!$group instanceof ElggGroup) {
869
		return;
870
	}
871
872
	$actions = [];
873
874
	if ($group->canEdit()) {
875
		// group owners can edit the group and invite new members
876
		$actions['groups:edit'] = "groups/edit/{$group->guid}";
877
		$actions['groups:invite'] = "groups/invite/{$group->guid}";
878
	}
879
880
	$user = elgg_get_logged_in_user_entity();
881
	if ($user && $group->isMember($user)) {
882
		if ($group->owner_guid != $user->guid) {
883
			// a member can leave a group if he/she doesn't own it
884
			$actions['groups:leave'] = "action/groups/leave?group_guid={$group->guid}";
885
		}
886
	} else if ($user) {
887
		$url = "action/groups/join?group_guid={$group->guid}";
888
		if ($group->isPublicMembership() || $group->canEdit()) {
889
			// admins can always join
890
			// non-admins can join if membership is public
891
			$actions['groups:join'] = $url;
892
		} else {
893
			// request membership
894
			$actions['groups:joinrequest'] = $url;
895
		}
896
	}
897
898
	foreach ($actions as $action => $url) {
899
		$items[] = ElggMenuItem::factory(array(
900
			'name' => $action,
901
			'href' => elgg_normalize_url($url),
902
			'text' => elgg_echo($action),
903
			'is_action' => 0 === strpos($url, 'action'),
904
			'link_class' => 'elgg-button elgg-button-action',
905
		));
906
	}
907
908
	return $items;
909
}
910
911
/**
912
 * Helper handler to correctly resolve page owners on group routes
913
 *
914
 * @see default_page_owner_handler()
915
 *
916
 * @param string $hook   "page_owner"
917
 * @param string $type   "system"
918
 * @param int    $return Page owner guid
919
 * @param array  $params Hook params
920
 * @return int|void
921
 */
922
function groups_default_page_owner_handler($hook, $type, $return, $params) {
923
924
	if ($return) {
925
		return;
926
	}
927
928
	$segments = _elgg_services()->request->getUrlSegments();
929
	$identifier = array_shift($segments);
930
931
	if ($identifier !== 'groups') {
932
		return;
933
	}
934
935
	$page = array_shift($segments);
936
937
	switch ($page) {
938
939
		case 'add' :
940
			$guid = array_shift($segments);
941
			if (!$guid) {
942
				$guid = elgg_get_logged_in_user_guid();
943
			}
944
			return $guid;
945
946
		case 'edit':
947
		case 'profile' :
948
		case 'activity' :
949
		case 'invite' :
950
		case 'requests' :
951
		case 'members' :
952
		case 'profile' :
953
			$guid = array_shift($segments);
954
			if (!$guid) {
955
				return;
956
			}
957
			return $guid;
958
959
		case 'member' :
960
		case 'owner' :
961
		case 'invitations':
962
			$username = array_shift($segments);
963
			if ($username) {
964
				$user = get_user_by_username($username);
965
			} else {
966
				$user = elgg_get_logged_in_user_entity();
967
			}
968
			if (!$user) {
969
				return;
970
			}
971
			return $user->guid;
972
	}
973
}
974
975
/**
976
 * Setup filter tabs on /groups/all page
977
 *
978
 * @param string         $hook   "register"
979
 * @param string         $type   "menu:filter:groups/all"
980
 * @param ElggMenuItem[] $return Menu
981
 * @param array          $params Hook params
982
 * @return ElggMenuItem[]
983
 */
984
function groups_setup_filter_tabs($hook, $type, $return, $params) {
985
986
	$filter_value = elgg_extract('filter_value', $params);
987
988
	$return[] = ElggMenuItem::factory([
989
		'name' => 'newest',
990
		'text' => elgg_echo('sort:newest'),
991
		'href' => 'groups/all?filter=newest',
992
		'priority' => 200,
993
		'selected' => $filter_value == 'newest',
994
	]);
995
996
	$return[] = ElggMenuItem::factory([
997
		'name' => 'alpha',
998
		'text' => elgg_echo('sort:alpha'),
999
		'href' => 'groups/all?filter=alpha',
1000
		'priority' => 250,
1001
		'selected' => $filter_value == 'alpha',
1002
	]);
1003
1004
	$return[] = ElggMenuItem::factory([
1005
		'name' => 'popular',
1006
		'text' => elgg_echo('sort:popular'),
1007
		'href' => 'groups/all?filter=popular',
1008
		'priority' => 300,
1009
		'selected' => $filter_value == 'popular',
1010
	]);
1011
1012
	$return[] = ElggMenuItem::factory([
1013
		'name' => 'featured',
1014
		'text' => elgg_echo('groups:featured'),
1015
		'href' => 'groups/all?filter=featured',
1016
		'priority' => 400,
1017
		'selected' => $filter_value == 'featured',
1018
	]);
1019
	
1020
	return $return;
1021
}
1022
1023
/**
1024
 * Add 'original' to group icon sizes
1025
 *
1026
 * @elgg_plugin_hook entity:icon:sizes group
1027
 * 
1028
 * @param \Elgg\Hook $hook Hook
1029
 * @return array
1030
 */
1031
function groups_set_icon_sizes(\Elgg\Hook $hook) {
1032
1033
	$sizes = $hook->getValue();
1034
	$sizes['original'] = [];
1035
1036
	return $sizes;
1037
}
1038