* @link https://getkirby.com * @copyright Bastian Allgeier * @license https://getkirby.com/license */ trait AppUsers { protected Auth|null $auth = null; protected User|string|null $user = null; protected Users|null $users = null; /** * Returns the Authentication layer class */ public function auth(): Auth { return $this->auth ??= new Auth($this); } /** * Become any existing user or disable the current user * * @param string|null $who User ID or email address, * `null` to use the actual user again, * `'kirby'` for a virtual admin user or * `'nobody'` to disable the actual user * @param Closure|null $callback Optional action function that will be run with * the permissions of the impersonated user; the * impersonation will be reset afterwards * @return mixed If called without callback: User that was impersonated; * if called with callback: Return value from the callback * @throws \Throwable */ public function impersonate( string|null $who = null, Closure|null $callback = null ): mixed { $auth = $this->auth(); $userBefore = $auth->currentUserFromImpersonation(); $userAfter = $auth->impersonate($who); if ($callback === null) { return $userAfter; } try { return $callback($userAfter); } catch (Throwable $e) { throw $e; } finally { // ensure that the impersonation is *always* reset // to the original value, even if an error occurred $auth->impersonate($userBefore?->id()); } } /** * Returns all user roles */ public function roles(): Roles { return $this->roles ??= Roles::load($this->root('roles')); } /** * Returns a specific user role by id * or the role of the current user if no id is given * * @param bool $allowImpersonation If set to false, only the role of the * actually logged in user will be returned * (when `$id` is passed as `null`) */ public function role( string|null $id = null, bool $allowImpersonation = true ): Role|null { if ($id !== null) { return $this->roles()->find($id); } return $this->user(null, $allowImpersonation)?->role(); } /** * Set the currently active user id * * @return $this */ protected function setUser(User|string|null $user = null): static { $this->user = $user; return $this; } /** * Create your own set of app users * * @return $this */ protected function setUsers(array|null $users = null): static { if ($users !== null) { $this->users = Users::factory($users); } return $this; } /** * Returns a specific user by id * or the current user if no id is given * * @param bool $allowImpersonation If set to false, only the actually * logged in user will be returned * (when `$id` is passed as `null`) */ public function user( string|null $id = null, bool $allowImpersonation = true ): User|null { if ($id !== null) { return $this->users()->find($id); } if ($allowImpersonation === true && is_string($this->user) === true) { return $this->auth()->impersonate($this->user); } try { return $this->auth()->user(null, $allowImpersonation); } catch (Throwable) { return null; } } /** * Returns all users */ public function users(): Users { return $this->users ??= Users::load( $this->root('accounts'), ); } }