model = $this->createModel($model); $query = $this->model->newModelQuery(); $query->with('stat'); if ($filter instanceof Closure) { # model should be inited before calling filter closure $filter = $filter($this); } $query->where($filter); $this->setModel($query->first()); $this->setSession($session ?? bff('session.store')); if ($this->model !== null) { $this->syncLang(); } } /** * @param \bff\db\illuminate\Model|\modules\users\models\User|null $model */ public function setModel($model) { $this->model = $model; if ($model !== null) { $this->modelAttributes = array_keys($model->getAttributes() ?? []); $this->statAttributes = array_keys($this->stat()->getAttributes() ?? []); } } /** * @return \bff\db\illuminate\Model|\modules\users\models\User */ public function getModel() { return $this->model; } /** * Create a new instance of the model. * @param string $model * @return \bff\db\illuminate\Model|\modules\users\models\User */ protected function createModel(string $model) { $class = '\\' . ltrim($model, '\\'); return new $class(); } /** * @param \Illuminate\Contracts\Session\Session $session */ public function setSession($session) { $this->session = $session; } /** * Get the unique identifier for the user. * @return mixed */ public function id() { return $this->getAuthIdentifier(); } /** * Compare identifier of the user. * @param mixed $id * @return bool */ public function isCurrent($id): bool { return !empty($id) && ($this->id() == $id); } /** * Compare user password * @param string $password open password * @return bool */ public function isCurrentPassword(string $password): bool { return bff::security()->passwordCheck( $password, $this->getAuthPassword(), $this->data('password_salt') ); } /** * Set user data (without saving) * @param string|array $key * @param mixed $value * @return void */ public function set($key, $value = null) { if (!is_array($key)) { $key = [$key => $value]; } $idKey = $this->getAuthIdentifier(); foreach ($key as $k => $v) { if ($k == $idKey) { continue; } if (in_array($k, $this->modelAttributes, true)) { $this->model->setAttribute($k, $v); } elseif (in_array($k, $this->statAttributes, true)) { $this->stat()->setAttribute($k, $v); } else { $this->session->put($k, $v); } } } /** * Set & save user data * @param string|array $key * @param mixed $value * @return void */ public function update($key, $value = null) { if (!is_array($key)) { $key = [$key => $value]; } $keys = collect($key); $this->model->update($keys->only($this->modelAttributes)->toArray()); $this->stat()->update($keys->only($this->statAttributes)->toArray()); if ($this->session) { $session = $keys->except($this->modelAttributes)->except($this->statAttributes); if ($session->isNotEmpty()) { $this->session->put($session->toArray()); $this->session->save(); } } } /** * Get user data * @param string|array $key * @param mixed $default * @return mixed|array */ public function data($key, $default = null) { if (is_array($key)) { $data = []; foreach ($key as $k) { $data[$k] = $this->data($k); } return $data; } return ( $this->model->getAttribute($key) ?? $this->stat()->getAttribute($key) ?? $this->session($key, $default) ?? $default ); } /** * Get user session data * @param string|array $key * @param mixed $default * @return mixed */ public function session($key, $default = null) { if ($this->session) { return $this->session->get($key, $default); } return $default; } /** * User stat data model * @return \bff\modules\users\models\UserStat|\Illuminate\Support\Optional|mixed */ protected function stat() { return optional($this->model->stat); } /** * Update stat data on login event * @param array|null */ public function touchOnLogin(?array $data = null) { if (empty($data)) { $now = date('Y-m-d H:i:s'); $data = [ 'last_activity' => $now, 'last_login' => $now, 'last_login2' => $this->data('last_login'), 'last_login_ip' => Request::remoteAddress(true), 'session_id' => $this->session->getId(), ]; } $this->stat()->update($data); } /** * Refresh user data */ public function refresh() { if ($this->model) { $this->model->refresh(); } } /** * User email * @return string */ public function email() { return $this->data('email', ''); } /** * User login * @return string */ public function login() { return $this->data('login', ''); } /** * User avatar url * @param string|null $size * @param string $default url * @return string */ public function avatar(?string $size = null, string $default = '') { return UsersAvatar::url( $this->id(), $this->data('avatar', ''), $size, $this->data('sex') ); } /** * User language * @return string */ public function lang() { return $this->data('lang', Lang::current()); } /** * Sync user language switch * @param string|null $language */ protected function syncLang(?string $language = null) { $language = $language ?? Lang::getLanguageCookie(); if ( sizeof(Lang::getLanguages()) > 1 && $this->data('lang') !== $language ) { $this->update('lang', $language); } } /** * User balance * @param bool $refresh * @return float */ public function balance($refresh = false) { if ($refresh) { $this->refresh(); } return floatval($this->data('balance', 0)); } /** * User counter value * @param string $key * @param int $default * @return int */ public function counter(string $key, int $default = 0) { return (int)($this->stat()->getAttribute($key) ?? $default); } /** * Update user counter value * @param string $key * @param int $amount * @param bool $incrementDecrement true +/-, false - set new amount */ public function counterChange(string $key, int $amount, bool $incrementDecrement = true) { if ($incrementDecrement) { $this->stat()->increment($key, $amount); } else { $this->stat()->update([$key => $amount]); } } /** * User counters values * @param array $keys * @param string|null $prefix * @return array */ public function counters(array $keys = [], ?string $prefix = null) { if (! is_string($prefix)) { $prefix = ''; } if (empty($keys)) { # All counters, todo: exclude other stat data $keys = $this->statAttributes; } $values = []; foreach ($keys as $key) { $values[$prefix . $key] = $this->stat()->getAttribute($key); } return $values; } /** * Get user groups * @return array */ public function getGroups() { if (is_null($this->groups)) { $this->groups = []; foreach ($this->model->groups()->with('group')->get() as $in) { $this->groups[intval($in->group_id)] = $in->group->keyword; } } return $this->groups; } /** * Is user in group * @param int|string|array $group * @return bool */ public function isInGroup($group): bool { if (is_array($group)) { foreach ($group as $id) { if ($this->isInGroup($id)) { return true; } } return false; } $groups = $this->getGroups(); if (empty($groups)) { return false; } if (is_int($group) && $group > 0) { return array_key_exists($group, $groups); } return in_array($group, $groups, true); } /** * Is administrator (in group). * @param mixed $group * @return bool */ public function admin($group = null): bool { if (! (bool)$this->data('admin', false)) { return false; } if (! is_null($group) && !$this->isInGroup($group)) { return false; } return true; } /** * Is super administrator. * @return bool */ public function superAdmin(): bool { return $this->isInGroup(Users::GROUPID_SUPERADMIN); } /** * Is administrator with access to module (and scope). * @param string $module * @param string|array|null $scope * @return bool */ public function hasAccessTo(string $module, $scope = null): bool { if (! $this->admin()) { return false; } if ($this->superAdmin()) { # Super administrator has full access return true; } return $this->hasAccessToModuleScope($module, $scope); } /** * Get permissions list * @return array */ public function getPermissions() { # Lazy load permissions if (is_null($this->permissions)) { $this->setPermissions( Users::model()->userGroupsPermissions($this->id(), array_keys($this->getGroups())) ); } return $this->permissions; } /** * Get the name of the unique identifier for the user. * @return string */ public function getAuthIdentifierName() { return $this->model->getKeyName(); } /** * Get the unique identifier for the user. * @return mixed */ public function getAuthIdentifier() { return $this->data($this->getAuthIdentifierName(), 0); } /** * Get the password for the user. * @return string */ public function getAuthPassword() { return $this->data('password', ''); } /** * Get the token value for the "remember me" session. * @return string|null */ public function getRememberToken() { if (! empty($this->getRememberTokenName())) { return (string) $this->data($this->getRememberTokenName(), ''); } return ''; } /** * Set & save the token value for the "remember me" session. * @param string $value * @return void */ public function setRememberToken($value) { if (! empty($this->getRememberTokenName())) { $this->set($this->getRememberTokenName(), $value); } } /** * Get the column name for the "remember me" token. * @return string */ public function getRememberTokenName() { return $this->rememberTokenName; } /** * Validate a user against the given credentials. * @param array $credentials * @return bool */ public function validateCredentials(array $credentials) { return $this->isCurrentPassword($credentials['password'] ?? ''); } }