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 | 498 | public function __construct(PluginHooksService $hooks, EntityTable $entities, ElggSession $session) { |
|
48 | 498 | $this->hooks = $hooks; |
|
49 | 498 | $this->entities = $entities; |
|
50 | 498 | $this->session = $session; |
|
51 | 498 | } |
|
52 | |||
53 | /** |
||
54 | * Decides if the access system should be ignored for a user. |
||
55 | * |
||
56 | * Returns true (meaning ignore access) if either of these 2 conditions are true: |
||
57 | * 1) an admin user guid is passed to this function. |
||
58 | * 2) {@link elgg_get_ignore_access()} returns true. |
||
59 | * |
||
60 | * @see elgg_set_ignore_access() |
||
61 | * |
||
62 | * @param int $user_guid The user to check against. |
||
63 | * |
||
64 | * @return bool |
||
65 | */ |
||
66 | 1251 | public function canBypassPermissionsCheck($user_guid = 0) { |
|
67 | 1251 | if ($this->session->getIgnoreAccess()) { |
|
68 | // Checking ignored access first to avoid infinite loops, |
||
69 | // when trying to fetch a user by guid |
||
70 | 632 | return true; |
|
71 | } |
||
72 | |||
73 | try { |
||
74 | 1226 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
75 | 6 | } catch (UserFetchFailureException $e) { |
|
76 | 6 | return false; |
|
77 | } |
||
78 | |||
79 | 1220 | return $user && $user->isAdmin(); |
|
80 | } |
||
81 | |||
82 | /** |
||
83 | * Can a user edit this entity? |
||
84 | * |
||
85 | * @tip Can be overridden by registering for the permissions_check plugin hook. |
||
86 | * |
||
87 | * @param ElggEntity $entity Object entity |
||
88 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||
89 | * |
||
90 | * @return bool Whether this entity is editable by the given user. |
||
91 | * @see elgg_set_ignore_access() |
||
92 | */ |
||
93 | 399 | public function canEdit(ElggEntity $entity, $user_guid = 0) { |
|
94 | 399 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
95 | 189 | return true; |
|
96 | } |
||
97 | |||
98 | try { |
||
99 | 318 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
100 | } catch (UserFetchFailureException $e) { |
||
101 | return false; |
||
102 | } |
||
103 | |||
104 | // Test user if possible - should default to false unless a plugin hook says otherwise |
||
105 | 318 | $default = call_user_func(function () use ($entity, $user) { |
|
106 | 318 | if (!$user) { |
|
107 | 275 | return false; |
|
108 | } |
||
109 | |||
110 | // favor the persisted attributes if not saved |
||
111 | 44 | $attrs = array_merge( |
|
112 | [ |
||
113 | 44 | 'owner_guid' => $entity->owner_guid, |
|
114 | 44 | 'container_guid' => $entity->container_guid, |
|
115 | 44 | ], $entity->getOriginalAttributes() |
|
116 | ); |
||
117 | |||
118 | 44 | if ($attrs['owner_guid'] == $user->guid) { |
|
119 | 38 | return true; |
|
120 | } |
||
121 | |||
122 | 34 | if ($attrs['container_guid'] == $user->guid) { |
|
123 | 3 | return true; |
|
124 | } |
||
125 | |||
126 | 34 | if ($entity->guid == $user->guid) { |
|
127 | 24 | return true; |
|
128 | } |
||
129 | |||
130 | 14 | $container = $this->entities->get($attrs['container_guid']); |
|
131 | |||
132 | 14 | return ($container && $container->canEdit($user->guid)); |
|
133 | 318 | }); |
|
134 | |||
135 | 318 | $params = ['entity' => $entity, 'user' => $user]; |
|
136 | 318 | return $this->hooks->trigger('permissions_check', $entity->getType(), $params, $default); |
|
137 | } |
||
138 | |||
139 | /** |
||
140 | * Can a user delete this entity? |
||
141 | * |
||
142 | * @tip Can be overridden by registering for the permissions_check:delete plugin hook. |
||
143 | * |
||
144 | * @param ElggEntity $entity Object entity |
||
145 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||
146 | * |
||
147 | * @return bool Whether this entity is deletable by the given user. |
||
148 | * @since 1.11 |
||
149 | * @see elgg_set_ignore_access() |
||
150 | */ |
||
151 | 462 | public function canDelete(ElggEntity $entity, $user_guid = 0) { |
|
152 | 462 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
153 | 200 | return true; |
|
154 | } |
||
155 | |||
156 | try { |
||
157 | 272 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
158 | } catch (UserFetchFailureException $e) { |
||
159 | return false; |
||
160 | } |
||
161 | |||
162 | 272 | $return = $entity->canEdit($user_guid); |
|
163 | |||
164 | $params = [ |
||
165 | 272 | 'entity' => $entity, |
|
166 | 272 | 'user' => $user |
|
167 | ]; |
||
168 | 272 | return $this->hooks->trigger('permissions_check:delete', $entity->getType(), $params, $return); |
|
169 | } |
||
170 | |||
171 | /** |
||
172 | * Can a user delete this river item? |
||
173 | * |
||
174 | * @tip Can be overridden by registering for the "permissions_check:delete", "river" plugin hook. |
||
175 | * |
||
176 | * @param ElggRiverItem $item River item |
||
177 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||
178 | * |
||
179 | * @return bool Whether this river item should be considered deletable by the given user. |
||
180 | * @since 2.3 |
||
181 | * @see elgg_set_ignore_access() |
||
182 | */ |
||
183 | 11 | public function canDeleteRiverItem(ElggRiverItem $item, $user_guid = 0) { |
|
184 | 11 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
185 | 5 | return true; |
|
186 | } |
||
187 | |||
188 | try { |
||
189 | 6 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
190 | } catch (UserFetchFailureException $e) { |
||
191 | return false; |
||
192 | } |
||
193 | |||
194 | $params = [ |
||
195 | 6 | 'item' => $item, |
|
196 | 6 | 'user' => $user, |
|
197 | ]; |
||
198 | 6 | return $this->hooks->trigger('permissions_check:delete', 'river', $params, false); |
|
199 | } |
||
200 | |||
201 | /** |
||
202 | * Can a user edit metadata on this entity? |
||
203 | * |
||
204 | * If no specific metadata is passed, it returns whether the user can |
||
205 | * edit any metadata on the entity. |
||
206 | * |
||
207 | * @tip Can be overridden by by registering for the permissions_check:metadata |
||
208 | * plugin hook. |
||
209 | * |
||
210 | * @param ElggEntity $entity Object entity |
||
211 | * @param int $user_guid The user GUID, optionally (default: logged in user) |
||
212 | * @param ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata |
||
213 | * |
||
214 | * @return bool |
||
215 | * @see elgg_set_ignore_access() |
||
216 | */ |
||
217 | 338 | public function canEditMetadata(ElggEntity $entity, $user_guid = 0, ElggMetadata $metadata = null) { |
|
218 | 338 | if (!$entity->guid) { |
|
219 | // @todo cannot edit metadata on unsaved entity? |
||
220 | 1 | return false; |
|
221 | } |
||
222 | |||
223 | 337 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
224 | 293 | return true; |
|
225 | } |
||
226 | |||
227 | try { |
||
228 | 63 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
229 | } catch (UserFetchFailureException $e) { |
||
230 | return false; |
||
231 | } |
||
232 | |||
233 | 63 | if ($user) { |
|
234 | 10 | $user_guid = $user->guid; |
|
235 | } |
||
236 | |||
237 | // if metadata is not owned or owned by the user, then can edit |
||
238 | 63 | if ($metadata && ($metadata->owner_guid == 0 || $metadata->owner_guid == $user_guid)) { |
|
239 | 62 | $return = true; |
|
240 | } else { |
||
241 | 2 | $return = $entity->canEdit($user_guid); |
|
242 | } |
||
243 | |||
244 | // metadata and user may be null |
||
245 | $params = [ |
||
246 | 63 | 'entity' => $entity, |
|
247 | 63 | 'user' => $user, |
|
248 | 63 | 'metadata' => $metadata |
|
249 | ]; |
||
250 | 63 | return $this->hooks->trigger('permissions_check:metadata', $entity->getType(), $params, $return); |
|
251 | } |
||
252 | |||
253 | /** |
||
254 | * Determines whether or not the user can edit this annotation |
||
255 | * |
||
256 | * @param Elggentity $entity Object entity |
||
257 | * @param int $user_guid The GUID of the user (defaults to currently logged in user) |
||
258 | * @param ElggAnnotation $annotation Annotation |
||
259 | * |
||
260 | * @return bool |
||
261 | * @see elgg_set_ignore_access() |
||
262 | */ |
||
263 | 35 | public function canEditAnnotation(ElggEntity $entity, $user_guid = 0, ElggAnnotation $annotation = null) { |
|
264 | 35 | if (!$annotation) { |
|
265 | return false; |
||
266 | } |
||
267 | |||
268 | 35 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
269 | 33 | return true; |
|
270 | } |
||
271 | |||
272 | try { |
||
273 | 5 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
274 | } catch (UserFetchFailureException $e) { |
||
275 | return false; |
||
276 | } |
||
277 | |||
278 | 5 | $result = false; |
|
279 | |||
280 | 5 | if ($user) { |
|
281 | // If the owner of annotation is the specified user, they can edit. |
||
282 | 5 | if ($annotation->owner_guid == $user->guid) { |
|
283 | 4 | $result = true; |
|
284 | } |
||
285 | |||
286 | // If the user can edit the entity this is attached to, they can edit. |
||
287 | 5 | if ($result == false && $entity->canEdit($user->guid)) { |
|
288 | 1 | $result = true; |
|
289 | } |
||
290 | } |
||
291 | |||
292 | // Trigger plugin hook - note that $user may be null |
||
293 | $params = [ |
||
294 | 5 | 'entity' => $entity, |
|
295 | 5 | 'user' => $user, |
|
296 | 5 | 'annotation' => $annotation |
|
297 | ]; |
||
298 | |||
299 | 5 | return $this->hooks->trigger('permissions_check', 'annotation', $params, $result); |
|
300 | } |
||
301 | |||
302 | /** |
||
303 | * Can a user add an entity to this container |
||
304 | * |
||
305 | * @param ElggEntity $entity Container entity |
||
306 | * @param int $user_guid The GUID of the user creating the entity (0 for logged in user). |
||
307 | * @param string $type The type of entity we're looking to write |
||
308 | * @param string $subtype The subtype of the entity we're looking to write |
||
309 | * |
||
310 | * @return bool |
||
311 | * @see elgg_set_ignore_access() |
||
312 | */ |
||
313 | 407 | public function canWriteToContainer(ElggEntity $entity, $user_guid = 0, $type = 'all', $subtype = 'all') { |
|
314 | try { |
||
315 | 407 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
316 | } catch (UserFetchFailureException $e) { |
||
317 | return false; |
||
318 | } |
||
319 | |||
320 | 407 | if ($user) { |
|
321 | 221 | $user_guid = $user->guid; |
|
322 | } |
||
323 | |||
324 | $params = [ |
||
325 | 407 | 'container' => $entity, |
|
326 | 407 | 'user' => $user, |
|
327 | 407 | 'subtype' => $subtype |
|
328 | ]; |
||
329 | |||
330 | // Unlike permissions, logic check can be used to prevent certain entity |
||
331 | // types from being contained by other entity types, |
||
332 | // e.g. discussion reply objects can only be contained by discussion objects. |
||
333 | // This hook can also be used to apply status logic, e.g. to disallow |
||
334 | // new replies in closed discussions. |
||
335 | // We do not take a stand hence the return is null. This can be used by |
||
336 | // handlers to check if another hook has modified the value. |
||
337 | 407 | $logic_check = $this->hooks->trigger('container_logic_check', $type, $params); |
|
0 ignored issues
–
show
|
|||
338 | |||
339 | 407 | if ($logic_check === false) { |
|
340 | 2 | return false; |
|
341 | } |
||
342 | |||
343 | 407 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
344 | 399 | return true; |
|
345 | } |
||
346 | |||
347 | 15 | $return = false; |
|
348 | 15 | if ($entity) { |
|
349 | // If the user can edit the container, they can also write to it |
||
350 | 15 | if ($entity->canEdit($user_guid)) { |
|
351 | 12 | $return = true; |
|
352 | } |
||
353 | } |
||
354 | |||
355 | // Container permissions can prevent users from writing to an entity. |
||
356 | // For instance, these permissions can prevent non-group members from writing |
||
357 | // content to the group. |
||
358 | 15 | return $this->hooks->trigger('container_permissions_check', $type, $params, $return); |
|
359 | } |
||
360 | |||
361 | /** |
||
362 | * Can a user comment on an entity? |
||
363 | * |
||
364 | * @tip Can be overridden by registering for the permissions_check:comment, |
||
365 | * <entity type> plugin hook. |
||
366 | * |
||
367 | * @param ElggEntity $entity Object entity |
||
368 | * @param int $user_guid User guid (default is logged in user) |
||
369 | * @param bool $default Default permission |
||
370 | * @return bool |
||
371 | */ |
||
372 | 4 | public function canComment(ElggEntity $entity, $user_guid = 0, $default = null) { |
|
373 | 4 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
374 | 2 | return true; |
|
375 | } |
||
376 | |||
377 | try { |
||
378 | 4 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
379 | } catch (UserFetchFailureException $e) { |
||
380 | return false; |
||
381 | } |
||
382 | |||
383 | // By default, we don't take a position of whether commenting is allowed |
||
384 | // because it is handled by the subclasses of \ElggEntity |
||
385 | $params = [ |
||
386 | 4 | 'entity' => $entity, |
|
387 | 4 | 'user' => $user |
|
388 | ]; |
||
389 | 4 | return $this->hooks->trigger('permissions_check:comment', $entity->getType(), $params, $default); |
|
390 | } |
||
391 | |||
392 | /** |
||
393 | * Can a user annotate an entity? |
||
394 | * |
||
395 | * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:<name>, |
||
396 | * <entity type>] or [permissions_check:annotate, <entity type>]. The hooks are called in that order. |
||
397 | * |
||
398 | * @tip If you want logged out users to annotate an object, do not call |
||
399 | * canAnnotate(). It's easier than using the plugin hook. |
||
400 | * |
||
401 | * @param ElggEntity $entity Objet entity |
||
402 | * @param int $user_guid User guid (default is logged in user) |
||
403 | * @param string $annotation_name The name of the annotation (default is unspecified) |
||
404 | * |
||
405 | * @return bool |
||
406 | */ |
||
407 | 8 | public function canAnnotate(ElggEntity $entity, $user_guid = 0, $annotation_name = '') { |
|
408 | 8 | if ($annotation_name === null || $annotation_name === false) { |
|
409 | // accepting these for BC |
||
410 | 1 | $annotation_name = ''; |
|
411 | 8 | } elseif (!is_string($annotation_name)) { |
|
412 | 4 | throw new InvalidArgumentException(__METHOD__ . ' expects \$annotation_name to be a string'); |
|
413 | } |
||
414 | |||
415 | 4 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
416 | 2 | return true; |
|
417 | } |
||
418 | |||
419 | try { |
||
420 | 4 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
421 | } catch (UserFetchFailureException $e) { |
||
422 | return false; |
||
423 | } |
||
424 | |||
425 | 4 | $return = (bool) $user; |
|
426 | |||
427 | $params = [ |
||
428 | 4 | 'entity' => $entity, |
|
429 | 4 | 'user' => $user, |
|
430 | 4 | 'annotation_name' => $annotation_name, |
|
431 | ]; |
||
432 | |||
433 | 4 | if (!empty($annotation_name)) { |
|
434 | 4 | $return = $this->hooks->trigger("permissions_check:annotate:$annotation_name", $entity->getType(), $params, $return); |
|
435 | } |
||
436 | |||
437 | 4 | return $this->hooks->trigger('permissions_check:annotate', $entity->getType(), $params, $return); |
|
438 | } |
||
439 | |||
440 | /** |
||
441 | * Can a user download a file? |
||
442 | * |
||
443 | * @tip Can be overridden by registering for the permissions_check:download,file plugin hook. |
||
444 | * |
||
445 | * @param ElggFile $entity File entity |
||
446 | * @param int $user_guid User guid (default is logged in user) |
||
447 | * @param bool $default Default permission |
||
448 | * |
||
449 | * @return bool |
||
450 | */ |
||
451 | 2 | public function canDownload(ElggFile $entity, $user_guid = 0, $default = true) { |
|
452 | 2 | if ($this->canBypassPermissionsCheck($user_guid)) { |
|
453 | 1 | return true; |
|
454 | } |
||
455 | |||
456 | try { |
||
457 | 2 | $user = $this->entities->getUserForPermissionsCheck($user_guid); |
|
458 | } catch (UserFetchFailureException $e) { |
||
459 | return false; |
||
460 | } |
||
461 | |||
462 | $params = [ |
||
463 | 2 | 'entity' => $entity, |
|
464 | 2 | 'user' => $user |
|
465 | ]; |
||
466 | |||
467 | 2 | return $this->hooks->trigger('permissions_check:download', 'file', $params, $default); |
|
468 | } |
||
469 | |||
470 | } |
||
471 |
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()
can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.