1<?php
2/**
3 * Elgg Pages
4 */
5
6require_once(dirname(__FILE__) . '/lib/pages.php');
7
8/**
9 * Initialize the pages plugin
10 *
11 * @return void
12 */
13function pages_init() {
14
15	// register a library of helper functions
16	\Elgg\Includer::requireFileOnce(__DIR__ . '/lib/pages.php');
17
18	elgg_register_menu_item('site', [
19		'name' => 'pages',
20		'icon' => 'file-text-o',
21		'text' => elgg_echo('collection:object:page'),
22		'href' => elgg_generate_url('default:object:page'),
23	]);
24
25	// Register a url handler
26	elgg_register_plugin_hook_handler('extender:url', 'annotation', 'pages_set_revision_url');
27
28	// Register for notifications
29	elgg_register_notification_event('object', 'page');
30	elgg_register_plugin_hook_handler('prepare', 'notification:create:object:page', 'pages_prepare_notification');
31
32	// add to groups
33	elgg()->group_tools->register('pages');
34
35	// Language short codes must be of the form "pages:key"
36	// where key is the array key below
37	elgg_set_config('pages', [
38		'title' => 'text',
39		'description' => 'longtext',
40		'tags' => 'tags',
41		'parent_guid' => 'pages/parent',
42		'access_id' => 'access',
43		'write_access_id' => 'access',
44	]);
45
46	elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'pages_owner_block_menu');
47	elgg_register_plugin_hook_handler('register', 'menu:pages_nav', '\Elgg\Pages\Menus::registerPageMenuItems');
48	elgg_register_plugin_hook_handler('prepare', 'menu:pages_nav', '_elgg_setup_vertical_menu', 999);
49
50	// write permission plugin hooks
51	elgg_register_plugin_hook_handler('permissions_check', 'object', 'pages_write_permission_check');
52	elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'pages_container_permission_check');
53
54	elgg_register_plugin_hook_handler('access:collections:write', 'user', 'pages_write_access_options_hook');
55
56	// icon url override
57	elgg_register_plugin_hook_handler('entity:icon:url', 'object', 'pages_icon_url_override');
58
59	// entity menu
60	elgg_register_plugin_hook_handler('register', 'menu:entity', 'pages_entity_menu_setup');
61
62	// register ecml views to parse
63	elgg_register_plugin_hook_handler('get_views', 'ecml', 'pages_ecml_views_hook');
64
65	// allow to be liked
66	elgg_register_plugin_hook_handler('likes:is_likable', 'object:page', 'Elgg\Values::getTrue');
67
68	// prevent public write access
69	elgg_register_plugin_hook_handler('view_vars', 'input/access', 'pages_write_access_vars');
70
71	// register database seed
72	elgg_register_plugin_hook_handler('seeds', 'database', 'pages_register_db_seeds');
73}
74
75/**
76 * Override the page annotation url
77 *
78 * @param \Elgg\Hook $hook 'extender:url', 'annotation'
79 *
80 * @return void|string
81 */
82function pages_set_revision_url(\Elgg\Hook $hook) {
83
84	$annotation = $hook->getParam('extender');
85	if ($annotation->getSubtype() == 'page') {
86		return elgg_generate_url('revision:object:page', [
87			'id' => $annotation->id,
88		]);
89	}
90}
91
92/**
93 * Override the default entity icon for pages
94 *
95 * @param \Elgg\Hook $hook 'entity:icon:url', 'object'
96 *
97 * @return string
98 */
99function pages_icon_url_override(\Elgg\Hook $hook) {
100	if ($hook->getEntityParam() instanceof ElggPage) {
101		return elgg_get_simplecache_url('pages/images/pages.gif');
102	}
103}
104
105/**
106 * Add a menu item to the user ownerblock
107 *
108 * @param \Elgg\Hook $hook 'register', 'menu:owner_block'
109 *
110 * @return ElggMenuItem[]
111 */
112function pages_owner_block_menu(\Elgg\Hook $hook) {
113
114	$entity = $hook->getEntityParam();
115	$return = $hook->getValue();
116
117	if ($entity instanceof ElggUser) {
118		$url = elgg_generate_url('collection:object:page:owner', [
119			'username' => $entity->username,
120		]);
121		$item = new ElggMenuItem('pages', elgg_echo('collection:object:page'), $url);
122		$return[] = $item;
123	} elseif ($entity instanceof ElggGroup) {
124		if ($entity->isToolEnabled('pages')) {
125			$url = elgg_generate_url('collection:object:page:group', [
126				'guid' => $entity->guid,
127				'subpage' => 'all',
128			]);
129			$item = new ElggMenuItem('pages', elgg_echo('collection:object:page:group'), $url);
130			$return[] = $item;
131		}
132	}
133
134	return $return;
135}
136
137/**
138 * Add links/info to entity menu particular to pages plugin
139 *
140 * @param \Elgg\Hook $hook 'register', 'menu:entity'
141 *
142 * @return void|ElggMenuItem[]
143 */
144function pages_entity_menu_setup(\Elgg\Hook $hook) {
145
146	$entity = $hook->getEntityParam();
147	if (!$entity instanceof ElggPage) {
148		return;
149	}
150
151	if (!$entity->canEdit()) {
152		return;
153	}
154
155	$return = $hook->getValue();
156	$return[] = \ElggMenuItem::factory([
157		'name' => 'history',
158		'icon' => 'history',
159		'text' => elgg_echo('pages:history'),
160		'href' => elgg_generate_url('history:object:page', [
161			'guid' => $entity->guid,
162		]),
163	]);
164
165	return $return;
166}
167
168/**
169 * Prepare a notification message about a new page
170 *
171 * @param \Elgg\Hook $hook 'prepare', 'notification:create:object:page' | 'notification:create:object:page_top'
172 *
173 * @return void|Elgg\Notifications\Notification
174 */
175function pages_prepare_notification(\Elgg\Hook $hook) {
176
177	$event = $hook->getParam('event');
178
179	$entity = $event->getObject();
180	if (!$entity instanceof ElggPage) {
181		return;
182	}
183
184	$owner = $event->getActor();
185	$language = $hook->getParam('language');
186
187	$descr = $entity->description;
188	$title = $entity->getDisplayName();
189
190	$notification = $hook->getValue();
191	$notification->subject = elgg_echo('pages:notify:subject', [$title], $language);
192	$notification->body = elgg_echo('pages:notify:body', [
193		$owner->getDisplayName(),
194		$title,
195		$descr,
196		$entity->getURL(),
197	], $language);
198	$notification->summary = elgg_echo('pages:notify:summary', [$entity->getDisplayName()], $language);
199	$notification->url = $entity->getURL();
200
201	return $notification;
202}
203
204/**
205 * Extend permissions checking to extend can-edit for write users.
206 *
207 * @param \Elgg\Hook $hook 'permissions_check', 'object'
208 *
209 * @return void|bool
210 */
211function pages_write_permission_check(\Elgg\Hook $hook) {
212
213	$entity = $hook->getEntityParam();
214	if (!$entity instanceof ElggPage) {
215		return;
216	}
217
218	$write_permission = (int) $entity->write_access_id;
219	$user = $hook->getUserParam();
220
221	if (empty($write_permission) || !$user instanceof ElggUser) {
222		return;
223	}
224
225	switch ($write_permission) {
226		case ACCESS_PRIVATE:
227			// Elgg's default decision is what we want
228			return;
229		default:
230			$list = get_access_array($user->guid);
231			if (in_array($write_permission, $list)) {
232				// user in the access collection
233				return true;
234			}
235			break;
236	}
237}
238
239/**
240 * Extend container permissions checking to extend container write access for write users, needed for personal pages
241 *
242 * @param \Elgg\Hook $hook 'container_permissions_check', 'object'
243 *
244 * @return void|bool
245 */
246function pages_container_permission_check(\Elgg\Hook $hook) {
247
248	if ($hook->getValue()) {
249		// already have access
250		return;
251	}
252
253	// check type/subtype
254	if ($hook->getType() !== 'object' || $hook->getParam('subtype') !== 'page') {
255		return;
256	}
257
258	$user = $hook->getUserParam();
259	if (!$user instanceof ElggUser) {
260		return;
261	}
262
263	// look up a page object given via input
264	$page_guid = (int) get_input('guid'); // defined by route
265	if (empty($page_guid)) {
266		// try the parent guid for use in the action
267		$page_guid = (int) get_input('parent_guid');
268	}
269	if (empty($page_guid)) {
270		return;
271	}
272
273	$page = get_entity($page_guid);
274	if (!$page instanceof ElggPage) {
275		return;
276	}
277
278	// check if the page write access is in the users read access array
279	return in_array($page->write_access_id, get_access_array($user->guid));
280}
281
282/**
283 * Return views to parse for pages.
284 *
285 * @param \Elgg\Hook $hook 'get_views', 'ecml'
286 *
287 * @return array
288 */
289function pages_ecml_views_hook(\Elgg\Hook $hook) {
290	$return_value = $hook->getValue();
291	$return_value['object/page'] = elgg_echo('item:object:page');
292	return $return_value;
293}
294
295/**
296 * Is the given value a page object?
297 *
298 * @param ElggObject $value the entity to check
299 *
300 * @return bool
301 * @internal
302 */
303function pages_is_page($value) {
304
305	if (!$value instanceof ElggObject) {
306		return false;
307	}
308
309	return in_array($value->getSubtype(), ['page', 'page_top']);
310}
311
312/**
313 * Return options for the write_access_id input
314 *
315 * @param \Elgg\Hook $hook 'access:collections:write', 'user'
316 *
317 * @return void|array
318 */
319function pages_write_access_options_hook(\Elgg\Hook $hook) {
320
321	$input_params = $hook->getParam('input_params');
322	$return_value = $hook->getValue();
323
324	if (empty($input_params) || !isset($return_value[ACCESS_PUBLIC])) {
325		return;
326	}
327
328	if (elgg_extract('entity_subtype', $input_params) !== 'page') {
329		return;
330	}
331
332	if (elgg_extract('purpose', $input_params) !== 'write') {
333		return;
334	}
335
336	unset($return_value[ACCESS_PUBLIC]);
337
338	return $return_value;
339}
340
341/**
342 * Called on view_vars, input/access hook
343 * Prevent ACCESS_PUBLIC from ending up as a write access option
344 *
345 * @param \Elgg\Hook $hook 'view_vars', 'input/access'
346 *
347 * @return void|array
348 */
349function pages_write_access_vars(\Elgg\Hook $hook) {
350	$return = $hook->getValue();
351	if (elgg_extract('name', $return) !== 'write_access_id' || elgg_extract('purpose', $return) !== 'write') {
352		return;
353	}
354
355	$value = (int) elgg_extract('value', $return);
356	if ($value !== ACCESS_PUBLIC && $value !== ACCESS_DEFAULT) {
357		return;
358	}
359
360	$default_access = get_default_access();
361
362	if ($value === ACCESS_PUBLIC || $default_access === ACCESS_PUBLIC) {
363		// is the value public, or default which resolves to public?
364		// if so we'll set it to logged in, the next most permissible write access level
365		$return['value'] = ACCESS_LOGGED_IN;
366	}
367
368	return $return;
369}
370
371/**
372 * Register database seed
373 *
374 * @param \Elgg\Hook $hook 'seeds', 'database'
375 * @return array
376 */
377function pages_register_db_seeds(\Elgg\Hook $hook) {
378
379	$seeds = $hook->getValue();
380
381	$seeds[] = \Elgg\Pages\Seeder::class;
382
383	return $seeds;
384}
385
386return function() {
387	elgg_register_event_handler('init', 'system', 'pages_init');
388};
389