Test Failed
Push — master ( 8c47c2...3acf9f )
by Steve
12:37
created

engine/classes/Elgg/UserCapabilities.php (1 issue)

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
namespace Elgg;
4
5
use Elgg\Database\EntityTable;
6
use Elgg\Database\EntityTable\UserFetchFailureException;
7
use ElggAnnotation;
8
use ElggEntity;
9
use ElggFile;
10
use ElggRiverItem;
11
use ElggMetadata;
12
use ElggSession;
13
use InvalidArgumentException;
14
15
/**
16
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
17
 *
18
 * Use the elgg_* versions instead.
19
 *
20
 * @access private
21
 * @since 2.2
22
 */
23
class UserCapabilities {
24
25
	/**
26
	 * @var PluginHooksService $hooks
27
	 */
28
	private $hooks;
29
30
	/**
31
	 * @var EntityTable
32
	 */
33
	private $entities;
34
35
	/**
36
	 * @var ElggSession
37
	 */
38
	private $session;
39
40
	/**
41
	 * Constructor
42
	 *
43
	 * @param PluginHooksService $hooks    Plugin hooks service
44
	 * @param EntityTable        $entities Entity table
45
	 * @param ElggSession        $session  Session
46
	 */
47 43
	public function __construct(PluginHooksService $hooks, EntityTable $entities, ElggSession $session) {
48 43
		$this->hooks = $hooks;
49 43
		$this->entities = $entities;
50 43
		$this->session = $session;
51 43
	}
52
53
	/**
54
	 * Can a user edit this entity?
55
	 *
56
	 * @tip Can be overridden by registering for the permissions_check plugin hook.
57
	 *
58
	 * @param ElggEntity $entity    Object entity
59
	 * @param int        $user_guid The user GUID, optionally (default: logged in user)
60
	 *
61
	 * @return bool Whether this entity is editable by the given user.
62
	 * @see elgg_set_ignore_access()
63
	 */
64 22
	public function canEdit(ElggEntity $entity, $user_guid = 0) {
65
		try {
66 22
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
67
		} catch (UserFetchFailureException $e) {
68
			return false;
69
		}
70
71
		// Test user if possible - should default to false unless a plugin hook says otherwise
72 22
		$default = call_user_func(function () use ($entity, $user) {
73 22
			if (!$user) {
74 1
				return false;
75
			}
76
77
			// favor the persisted attributes if not saved
78 21
			$attrs = array_merge(
79
					[
80 21
				'owner_guid' => $entity->owner_guid,
81 21
				'container_guid' => $entity->container_guid,
82 21
					], $entity->getOriginalAttributes()
83
			);
84
85 21
			if ($attrs['owner_guid'] == $user->guid) {
86 14
				return true;
87
			}
88
89 11
			if ($attrs['container_guid'] == $user->guid) {
90 3
				return true;
91
			}
92
93 11
			if ($entity->guid == $user->guid) {
94 2
				return true;
95
			}
96
97 10
			$container = $this->entities->get($attrs['container_guid']);
98
99 10
			return ($container && $container->canEdit($user->guid));
100 22
		});
101
102 22
		$params = ['entity' => $entity, 'user' => $user];
103 22
		return $this->hooks->trigger('permissions_check', $entity->getType(), $params, $default);
104
	}
105
106
	/**
107
	 * Can a user delete this entity?
108
	 *
109
	 * @tip Can be overridden by registering for the permissions_check:delete plugin hook.
110
	 *
111
	 * @param ElggEntity $entity    Object entity
112
	 * @param int        $user_guid The user GUID, optionally (default: logged in user)
113
	 *
114
	 * @return bool Whether this entity is deletable by the given user.
115
	 * @since 1.11
116
	 * @see elgg_set_ignore_access()
117
	 */
118 4 View Code Duplication
	public function canDelete(ElggEntity $entity, $user_guid = 0) {
0 ignored issues
show
This method 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...
119
		try {
120 4
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
121
		} catch (UserFetchFailureException $e) {
122
			return false;
123
		}
124
125 4
		$return = $entity->canEdit($user_guid);
126
127
		$params = [
128 4
			'entity' => $entity,
129 4
			'user' => $user
130
		];
131 4
		return $this->hooks->trigger('permissions_check:delete', $entity->getType(), $params, $return);
132
	}
133
134
	/**
135
	 * Can a user delete this river item?
136
	 *
137
	 * @tip Can be overridden by registering for the "permissions_check:delete", "river" plugin hook.
138
	 *
139
	 * @param ElggRiverItem $item      River item
140
	 * @param int           $user_guid The user GUID, optionally (default: logged in user)
141
	 *
142
	 * @return bool Whether this river item should be considered deletable by the given user.
143
	 * @since 2.3
144
	 * @see elgg_set_ignore_access()
145
	 */
146 View Code Duplication
	public function canDeleteRiverItem(ElggRiverItem $item, $user_guid = 0) {
147
		try {
148
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
149
		} catch (UserFetchFailureException $e) {
150
			return false;
151
		}
152
153
		$return = ($user && $user->isAdmin());
154
155
		$params = [
156
			'item' => $item,
157
			'user' => $user,
158
		];
159
		return $this->hooks->trigger('permissions_check:delete', 'river', $params, $return);
160
	}
161
162
	/**
163
	 * Can a user edit metadata on this entity?
164
	 *
165
	 * If no specific metadata is passed, it returns whether the user can
166
	 * edit any metadata on the entity.
167
	 *
168
	 * @tip Can be overridden by by registering for the permissions_check:metadata
169
	 * plugin hook.
170
	 *
171
	 * @param ElggEntity   $entity    Object entity
172
	 * @param int          $user_guid The user GUID, optionally (default: logged in user)
173
	 * @param ElggMetadata $metadata  The piece of metadata to specifically check or null for any metadata
174
	 *
175
	 * @return bool
176
	 * @see elgg_set_ignore_access()
177
	 */
178 8
	public function canEditMetadata(ElggEntity $entity, $user_guid = 0, ElggMetadata $metadata = null) {
179 8
		if (!$entity->guid) {
180
			// @todo cannot edit metadata on unsaved entity?
181 1
			return false;
182
		}
183
184
		try {
185 7
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
186
		} catch (UserFetchFailureException $e) {
187
			return false;
188
		}
189
190 7
		if ($user) {
191 7
			$user_guid = $user->guid;
192
		}
193
194
		// if metadata is not owned or owned by the user, then can edit
195 7
		if ($metadata && ($metadata->owner_guid == 0 || $metadata->owner_guid == $user_guid)) {
196 6
			$return = true;
197
		} else {
198 3
			$return = $entity->canEdit($user_guid);
199
		}
200
201
		// metadata and user may be null
202
		$params = [
203 7
			'entity' => $entity,
204 7
			'user' => $user,
205 7
			'metadata' => $metadata
206
		];
207 7
		return $this->hooks->trigger('permissions_check:metadata', $entity->getType(), $params, $return);
208
	}
209
210
	/**
211
	 * Determines whether or not the user can edit this annotation
212
	 *
213
	 * @param Elggentity     $entity     Object entity
214
	 * @param int            $user_guid  The GUID of the user (defaults to currently logged in user)
215
	 * @param ElggAnnotation $annotation Annotation
216
	 *
217
	 * @return bool
218
	 * @see elgg_set_ignore_access()
219
	 */
220 5
	public function canEditAnnotation(ElggEntity $entity, $user_guid = 0, ElggAnnotation $annotation = null) {
221 5
		if (!$annotation) {
222
			return false;
223
		}
224
		try {
225 5
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
226
		} catch (UserFetchFailureException $e) {
227
			return false;
228
		}
229
230 5
		$result = false;
231
232 5
		if ($user) {
233
			// If the owner of annotation is the specified user, they can edit.
234 5
			if ($annotation->owner_guid == $user->guid) {
235 4
				$result = true;
236
			}
237
238
			// If the user can edit the entity this is attached to, they can edit.
239 5
			if ($result == false && $entity->canEdit($user->guid)) {
240 1
				$result = true;
241
			}
242
		}
243
244
		// Trigger plugin hook - note that $user may be null
245
		$params = [
246 5
			'entity' => $entity,
247 5
			'user' => $user,
248 5
			'annotation' => $annotation
249
		];
250
251 5
		return $this->hooks->trigger('permissions_check', 'annotation', $params, $result);
252
	}
253
	
254
	/**
255
	 * Can a user add an entity to this container
256
	 *
257
	 * @param ElggEntity $entity    Container entity
258
	 * @param int        $user_guid The GUID of the user creating the entity (0 for logged in user).
259
	 * @param string     $type      The type of entity we're looking to write
260
	 * @param string     $subtype   The subtype of the entity we're looking to write
261
	 *
262
	 * @return bool
263
	 * @see elgg_set_ignore_access()
264
	 */
265 5
	public function canWriteToContainer(ElggEntity $entity, $user_guid = 0, $type = 'all', $subtype = 'all') {
266
		try {
267 5
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
268
		} catch (UserFetchFailureException $e) {
269
			return false;
270
		}
271
272 5
		if ($user) {
273 5
			$user_guid = $user->guid;
274
		}
275
276
		$params = [
277 5
			'container' => $entity,
278 5
			'user' => $user,
279 5
			'subtype' => $subtype
280
		];
281
282
		// Unlike permissions, logic check can be used to prevent certain entity
283
		// types from being contained by other entity types,
284
		// e.g. discussion reply objects can only be contained by discussion objects.
285
		// This hook can also be used to apply status logic, e.g. to disallow
286
		// new replies in closed discussions.
287
		// We do not take a stand hence the return is null. This can be used by
288
		// handlers to check if another hook has modified the value.
289 5
		$logic_check = $this->hooks->trigger('container_logic_check', $type, $params);
290
291 5
		if ($logic_check === false) {
292 1
			return false;
293
		}
294
		
295 5
		$return = false;
296 5
		if ($entity) {
297
			// If the user can edit the container, they can also write to it
298 5
			if ($entity->canEdit($user_guid)) {
299 4
				$return = true;
300
			}
301
		}
302
303
		// Container permissions can prevent users from writing to an entity.
304
		// For instance, these permissions can prevent non-group members from writing
305
		// content to the group.
306 5
		return $this->hooks->trigger('container_permissions_check', $type, $params, $return);
307
	}
308
309
	/**
310
	 * Can a user comment on an entity?
311
	 *
312
	 * @tip Can be overridden by registering for the permissions_check:comment,
313
	 * <entity type> plugin hook.
314
	 *
315
	 * @param ElggEntity $entity    Object entity
316
	 * @param int        $user_guid User guid (default is logged in user)
317
	 * @param bool       $default   Default permission
318
	 * @return bool
319
	 */
320 5 View Code Duplication
	public function canComment(ElggEntity $entity, $user_guid = 0, $default = null) {
321
		try {
322 5
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
323
		} catch (UserFetchFailureException $e) {
324
			return false;
325
		}
326
327
		// By default, we don't take a position of whether commenting is allowed
328
		// because it is handled by the subclasses of \ElggEntity
329
		$params = [
330 5
			'entity' => $entity,
331 5
			'user' => $user
332
		];
333 5
		return $this->hooks->trigger('permissions_check:comment', $entity->getType(), $params, $default);
334
	}
335
336
	/**
337
	 * Can a user annotate an entity?
338
	 *
339
	 * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>,
340
	 * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order.
341
	 *
342
	 * @tip If you want logged out users to annotate an object, do not call
343
	 * canAnnotate(). It's easier than using the plugin hook.
344
	 *
345
	 * @param ElggEntity $entity          Objet entity
346
	 * @param int        $user_guid       User guid (default is logged in user)
347
	 * @param string     $annotation_name The name of the annotation (default is unspecified)
348
	 *
349
	 * @return bool
350
	 */
351 8
	public function canAnnotate(ElggEntity $entity, $user_guid = 0, $annotation_name = '') {
352 8
		if ($annotation_name === null || $annotation_name === false) {
353
			// accepting these for BC
354 1
			$annotation_name = '';
355 8
		} elseif (!is_string($annotation_name)) {
356 4
			throw new InvalidArgumentException(__METHOD__ . ' expects \$annotation_name to be a string');
357
		}
358
359
		try {
360 4
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
361
		} catch (UserFetchFailureException $e) {
362
			return false;
363
		}
364
365 4
		$return = (bool) $user;
366
367
		$params = [
368 4
			'entity' => $entity,
369 4
			'user' => $user,
370 4
			'annotation_name' => $annotation_name,
371
		];
372
373 4
		if (!empty($annotation_name)) {
374 4
			$return = $this->hooks->trigger("permissions_check:annotate:$annotation_name", $entity->getType(), $params, $return);
375
		}
376
377 4
		return $this->hooks->trigger('permissions_check:annotate', $entity->getType(), $params, $return);
378
	}
379
380
	/**
381
	 * Can a user download a file?
382
	 *
383
	 * @tip Can be overridden by registering for the permissions_check:download,file plugin hook.
384
	 *
385
	 * @param ElggFile $entity    File entity
386
	 * @param int      $user_guid User guid (default is logged in user)
387
	 * @param bool     $default   Default permission
388
	 *
389
	 * @return bool
390
	 */
391 2
	public function canDownload(ElggFile $entity, $user_guid = 0, $default = true) {
392
		try {
393 2
			$user = $this->entities->getUserForPermissionsCheck($user_guid);
394
		} catch (UserFetchFailureException $e) {
395
			return false;
396
		}
397
398
		$params = [
399 2
			'entity' => $entity,
400 2
			'user' => $user
401
		];
402
403 2
		return $this->hooks->trigger('permissions_check:download', 'file', $params, $default);
404
	}
405
406
}
407