Elgg  Version master
UserCapabilities.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg;
4 
7 
15 
23  public function __construct(
24  protected EventsService $events,
25  protected EntityTable $entities,
26  protected SessionManagerService $session_manager
27  ) {
28  }
29 
41  public function canBypassPermissionsCheck(int $user_guid = 0): bool {
42  if ($this->session_manager->getIgnoreAccess()) {
43  // Checking ignored access first to avoid infinite loops,
44  // when trying to fetch a user by guid
45  return true;
46  }
47 
48  try {
49  $user = $this->entities->getUserForPermissionsCheck($user_guid);
50  } catch (UserFetchFailureException $e) {
51  return false;
52  }
53 
54  return $user && $user->isAdmin();
55  }
56 
67  public function canEdit(\ElggEntity $entity, int $user_guid = 0): bool {
68  if ($this->canBypassPermissionsCheck($user_guid)) {
69  return true;
70  }
71 
72  try {
73  $user = $this->entities->getUserForPermissionsCheck($user_guid);
74  } catch (UserFetchFailureException $e) {
75  return false;
76  }
77 
78  // Test user if possible - should default to false unless an event says otherwise
79  $default = call_user_func(function () use ($entity, $user) {
80  if (!$user) {
81  return false;
82  }
83 
84  // favor the persisted attributes if not saved
85  $attrs = array_merge([
86  'owner_guid' => $entity->owner_guid,
87  'container_guid' => $entity->container_guid,
88  ], $entity->getOriginalAttributes());
89 
90  if ($attrs['owner_guid'] == $user->guid) {
91  return true;
92  }
93 
94  if ($attrs['container_guid'] == $user->guid) {
95  return true;
96  }
97 
98  if ($entity->guid == $user->guid) {
99  return true;
100  }
101 
102  if (!isset($attrs['container_guid'])) {
103  return false;
104  }
105 
106  $container = $this->entities->get($attrs['container_guid']);
107 
108  return ($container && $container->canEdit($user->guid));
109  });
110 
111  $params = ['entity' => $entity, 'user' => $user];
112  return $this->events->triggerResults('permissions_check', $entity->getType(), $params, $default);
113  }
114 
126  public function canDelete(\ElggEntity $entity, int $user_guid = 0): bool {
127  if ($this->canBypassPermissionsCheck($user_guid)) {
128  return true;
129  }
130 
131  try {
132  $user = $this->entities->getUserForPermissionsCheck($user_guid);
133  } catch (UserFetchFailureException $e) {
134  return false;
135  }
136 
137  $return = $entity->canEdit($user_guid);
138 
139  $params = [
140  'entity' => $entity,
141  'user' => $user
142  ];
143  return $this->events->triggerResults('permissions_check:delete', $entity->getType(), $params, $return);
144  }
145 
157  public function canDeleteRiverItem(\ElggRiverItem $item, int $user_guid = 0): bool {
158  if ($this->canBypassPermissionsCheck($user_guid)) {
159  return true;
160  }
161 
162  try {
163  $user = $this->entities->getUserForPermissionsCheck($user_guid);
164  } catch (UserFetchFailureException $e) {
165  return false;
166  }
167 
168  $params = [
169  'item' => $item,
170  'user' => $user,
171  ];
172  return $this->events->triggerResults('permissions_check:delete', 'river', $params, false);
173  }
174 
184  public function canEditAnnotation(\ElggEntity $entity, int $user_guid = 0, \ElggAnnotation $annotation = null): bool {
185  if (!$annotation) {
186  return false;
187  }
188 
189  if ($this->canBypassPermissionsCheck($user_guid)) {
190  return true;
191  }
192 
193  try {
194  $user = $this->entities->getUserForPermissionsCheck($user_guid);
195  } catch (UserFetchFailureException $e) {
196  return false;
197  }
198 
199  $result = false;
200 
201  if ($user) {
202  // If the owner of annotation is the specified user, they can edit.
203  if ($annotation->owner_guid == $user->guid) {
204  $result = true;
205  }
206 
207  // If the user can edit the entity this is attached to, they can edit.
208  if ($result === false && $entity->canEdit($user->guid)) {
209  $result = true;
210  }
211  }
212 
213  // Trigger event - note that $user may be null
214  $params = [
215  'entity' => $entity,
216  'user' => $user,
217  'annotation' => $annotation,
218  ];
219 
220  return $this->events->triggerResults('permissions_check', 'annotation', $params, $result);
221  }
222 
233  public function canWriteToContainer(\ElggEntity $entity, string $type, string $subtype, int $user_guid = 0): bool {
234  try {
235  $user = $this->entities->getUserForPermissionsCheck($user_guid);
236  } catch (UserFetchFailureException $e) {
237  return false;
238  }
239 
240  if ($user) {
241  $user_guid = $user->guid;
242  }
243 
244  $params = [
245  'container' => $entity,
246  'user' => $user,
247  'subtype' => $subtype
248  ];
249 
250  // Unlike permissions, logic check can be used to prevent certain entity
251  // types from being contained by other entity types,
252  // e.g. discussion reply objects can only be contained by discussion objects.
253  // This event can also be used to apply status logic, e.g. to disallow
254  // new replies in closed discussions.
255  // We do not take a stand hence the return is null. This can be used by
256  // handlers to check if another event has modified the value.
257  $logic_check = $this->events->triggerResults('container_logic_check', $type, $params);
258 
259  if ($logic_check === false) {
260  return false;
261  }
262 
263  if ($this->canBypassPermissionsCheck($user_guid)) {
264  return true;
265  }
266 
267  // If the user can edit the container, they can also write to it
268  $return = $entity->canEdit($user_guid);
269 
270  // Container permissions can prevent users from writing to an entity.
271  // For instance, these permissions can prevent non-group members from writing
272  // content to the group.
273  return $this->events->triggerResults('container_permissions_check', $type, $params, $return);
274  }
275 
287  public function canComment(\ElggEntity $entity, int $user_guid = 0): bool {
288  try {
289  $user = $this->entities->getUserForPermissionsCheck($user_guid);
290  } catch (UserFetchFailureException $e) {
291  return false;
292  }
293 
294  $container_result = $this->canWriteToContainer($entity, 'object', 'comment', $user_guid);
295  if ($this->canBypassPermissionsCheck($user_guid)) {
296  // doing this again here to prevent bypassed users to be influenced by 'permissions_check:comment' event
297  return $container_result;
298  }
299 
300  // By default, we don't take a position of whether commenting is allowed
301  // because it is handled by the subclasses of \ElggEntity
302  $params = [
303  'entity' => $entity,
304  'user' => $user,
305  ];
306  return $this->events->triggerResults('permissions_check:comment', $entity->getType(), $params, $container_result);
307  }
308 
324  public function canAnnotate(\ElggEntity $entity, int $user_guid = 0, string $annotation_name = ''): bool {
325  if ($this->canBypassPermissionsCheck($user_guid)) {
326  return true;
327  }
328 
329  try {
330  $user = $this->entities->getUserForPermissionsCheck($user_guid);
331  } catch (UserFetchFailureException $e) {
332  return false;
333  }
334 
335  $return = (bool) $user;
336 
337  $params = [
338  'entity' => $entity,
339  'user' => $user,
340  'annotation_name' => $annotation_name,
341  ];
342 
343  if (!empty($annotation_name)) {
344  $return = $this->events->triggerResults("permissions_check:annotate:$annotation_name", $entity->getType(), $params, $return);
345  }
346 
347  return $this->events->triggerResults('permissions_check:annotate', $entity->getType(), $params, $return);
348  }
349 
361  public function canDownload(\ElggFile $entity, int $user_guid = 0, bool $default = true): bool {
362  if ($this->canBypassPermissionsCheck($user_guid)) {
363  return true;
364  }
365 
366  try {
367  $user = $this->entities->getUserForPermissionsCheck($user_guid);
368  } catch (UserFetchFailureException $e) {
369  return false;
370  }
371 
372  $params = [
373  'entity' => $entity,
374  'user' => $user
375  ];
376 
377  return $this->events->triggerResults('permissions_check:download', 'file', $params, $default);
378  }
379 }
canBypassPermissionsCheck(int $user_guid=0)
Decides if the access system should be ignored for a user.
$default
Definition: checkbox.php:30
if(!$items) $item
Definition: delete.php:13
$user_guid
Definition: login_as.php:10
$params
Saves global plugin settings.
Definition: save.php:13
__construct(protected EventsService $events, protected EntityTable $entities, protected SessionManagerService $session_manager)
Constructor.
if($id< 1) $annotation
Definition: delete.php:11
canDownload(\ElggFile $entity, int $user_guid=0, bool $default=true)
Can a user download a file?
Entity Annotation.
Events service.
canWriteToContainer(\ElggEntity $entity, string $type, string $subtype, int $user_guid=0)
Can a user add an entity to this container.
$type
Definition: delete.php:21
canEdit(int $user_guid=0)
Can a user edit this entity?
Definition: ElggEntity.php:932
canEditAnnotation(\ElggEntity $entity, int $user_guid=0,\ElggAnnotation $annotation=null)
Determines whether or not the user can edit this annotation.
$entity
Definition: reset.php:8
Exception indicating a user could not be looked up for a permissions check.
$user
Definition: ban.php:7
$container
Definition: delete.php:23
canEdit(\ElggEntity $entity, int $user_guid=0)
Can a user edit this entity?
canComment(\ElggEntity $entity, int $user_guid=0)
Can a user comment on an entity?
canAnnotate(\ElggEntity $entity, int $user_guid=0, string $annotation_name= '')
Can a user annotate an entity?
getType()
Returns the entity type.
$subtype
Definition: delete.php:22
getOriginalAttributes()
Get the original values of attribute(s) that have been modified since the entity was persisted...
Definition: ElggEntity.php:294
canDelete(\ElggEntity $entity, int $user_guid=0)
Can a user delete this entity?
canDeleteRiverItem(\ElggRiverItem $item, int $user_guid=0)
Can a user delete this river item?
User capabilities service.
if(empty($title)&&empty($body)) if(!empty($link)) $attrs
Definition: message.php:28
Entity table database service.
Definition: EntityTable.php:25