snapshot of https://github.com/espocrm/espocrm.git (master, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Test / Test on PHP 8.3 (push) Failing after 5s
Test / Test on PHP 8.4 (push) Failing after 4s
Test / Test on PHP 8.5 (push) Failing after 3s
TypeScript static analysis / TypeScript check (push) Failing after 14s
Test Integration on MySQL / Test on PHP 8.3 (push) Failing after 1s
Test Integration on MySQL / Test on PHP 8.5 (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 fix (push) Failing after 1s
Test Integration on PostgreSQL / Test on PHP 8.4 master (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-18 04:19:15 +05:00
commit 7cc7e6b4f3
10077 changed files with 900756 additions and 0 deletions

View File

@@ -0,0 +1,503 @@
<?php
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM – Open Source CRM application.
* Copyright (C) 2014-2026 EspoCRM, Inc.
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
namespace Espo\Entities;
use Espo\Core\Acl\Scope;
use Espo\Core\Entities\Person;
use Espo\Core\Field\Link;
use Espo\Core\Field\LinkMultiple;
use Espo\Core\Name\Field;
use Espo\Modules\Crm\Entities\Contact;
use LogicException;
use RuntimeException;
class User extends Person
{
public const ENTITY_TYPE = 'User';
public const ATTR_TYPE = 'type';
public const ATTR_IS_ACTIVE = 'isActive';
/**
* @internal
* @since 10.1.0
*/
public const string ATTR_PORTAL_ID = 'portalId';
/**
* @internal
* @since 10.1.0
*/
public const string ATTR_AUTH_TOKEN_ID = 'authTokenId';
/**
* @internal
* @since 10.1.0
*/
public const string ATTR_AUTH_LOG_RECORD_ID = 'authLogRecordId';
/** @since 10.1.0 */
public const string FIELD_IS_ACTIVE= 'isActive';
/** @since 10.0.0 */
public const string FIELD_USER_NAME = 'userName';
/** @since 10.0.0 */
public const string FIELD_PASSWORD = 'password';
/** @since 10.0.0 */
public const string FIELD_PASSWORD_VERSION = 'passwordVersion';
/** @since 10.0.0 */
public const string FIELD_TYPE = 'type';
/** @since 10.0.4 */
public const string FIELD_API_KEY = 'apiKey';
/** @since 10.1.0 */
public const string FIELD_SECRET_KEY = 'secretKey';
/** @since 10.0.4 */
public const string FIELD_AUTH_METHOD = 'authMethod';
/**
* @internal
* @since 10.1.0
*/
public const string FIELD_SCOPES = 'scopes';
/**
* @internal
* @since 10.1.0
*/
public const string FIELD_TOKEN = 'token';
/**
* @internal
* @since 10.1.0
*/
public const string FIELD_IP_ADDRESS = 'ipAddress';
public const LINK_ACCOUNTS = 'accounts';
public const LINK_CONTACT = 'contact';
public const LINK_PORTALS = 'portals';
public const LINK_TEAMS = 'teams';
public const LINK_DEFAULT_TEAM = 'defaultTeam';
public const LINK_ROLES = 'roles';
public const LINK_PORTAL_ROLES = 'portalRoles';
public const TYPE_PORTAL = 'portal';
public const TYPE_ADMIN = 'admin';
public const TYPE_SYSTEM = 'system';
public const TYPE_REGULAR = 'regular';
public const TYPE_API = 'api';
public const TYPE_SUPER_ADMIN = 'super-admin';
public const RELATIONSHIP_ENTITY_USER = 'EntityUser';
public const RELATIONSHIP_ENTITY_COLLABORATOR = 'EntityCollaborator';
/** @since 10.0.4 */
public const string AUTH_METHOD_API_KEY = 'ApiKey';
public function get(string $attribute): mixed
{
if ($attribute === Field::NAME) {
return $this->getNameInternal();
}
return parent::get($attribute);
}
public function has(string $attribute): bool
{
if ($attribute === Field::NAME) {
return $this->hasNameInternal();
}
return parent::has($attribute);
}
public function isActive(): bool
{
return (bool) $this->get('isActive');
}
/**
* @deprecated Use `isPortal`.
*/
public function isPortalUser(): bool
{
return $this->isPortal();
}
public function getType(): ?string
{
return $this->get('type');
}
/**
* @param self::TYPE_* $type
*/
public function setType(string $type): self
{
return $this->set('type', $type);
}
public function setUserName(?string $userName): self
{
return $this->set('userName', $userName);
}
/**
* Is regular user.
*/
public function isRegular(): bool
{
return $this->getType() === self::TYPE_REGULAR ||
($this->has('type') && !$this->getType());
}
/**
* Is admin, super-admin or system user.
*
* Do not use for access check for the current user. Use Acl::checkAdmin instead.
*/
public function isAdmin(): bool
{
return $this->getType() === self::TYPE_ADMIN ||
$this->isSystem() ||
$this->isSuperAdmin();
}
/**
* Is admin and is not stripped of admin capabilities.
*
* Prefer using Acl::checkAdmin instead.
*
* @since 10.1.0
*/
public function isEffectiveAdmin(): bool
{
if (!$this->isAdmin()) {
return false;
}
if ($this->getScopes() === null) {
return true;
}
if (!in_array(Scope::ADMIN, $this->getScopes())) {
return false;
}
return true;
}
/**
* Is portal user.
*/
public function isPortal(): bool
{
return $this->getType() === self::TYPE_PORTAL;
}
/**
* Is API user.
*/
public function isApi(): bool
{
return $this->getType() === self::TYPE_API;
}
/**
* Is system user.
*/
public function isSystem(): bool
{
return $this->getType() === self::TYPE_SYSTEM;
}
/**
* Is super-admin user.
*/
public function isSuperAdmin(): bool
{
return $this->getType() === self::TYPE_SUPER_ADMIN;
}
public function getRoles(): LinkMultiple
{
/** @var LinkMultiple */
return $this->getValueObject('roles');
}
public function getDefaultTeam(): ?Link
{
/** @var ?Link */
return $this->getValueObject('defaultTeam');
}
public function getWorkingTimeCalendar(): ?Link
{
/** @var ?Link */
return $this->getValueObject('workingTimeCalendar');
}
public function getLayoutSet(): ?Link
{
/** @var ?Link */
return $this->getValueObject('layoutSet');
}
public function getTeams(): LinkMultiple
{
/** @var LinkMultiple */
return $this->getValueObject('teams');
}
/**
* @return string[]
*/
public function getTeamIdList(): array
{
/** @var string[] */
return $this->getLinkMultipleIdList('teams');
}
public function setDefaultTeam(?Link $defaultTeam): self
{
$this->setValueObject('defaultTeam', $defaultTeam);
return $this;
}
public function setTeams(LinkMultiple $teams): self
{
$this->setValueObject('teams', $teams);
return $this;
}
public function getPortals(): LinkMultiple
{
/** @var LinkMultiple */
return $this->getValueObject('portals');
}
public function setPortals(LinkMultiple $portals): self
{
$this->setValueObject('portals', $portals);
return $this;
}
public function setRoles(LinkMultiple $roles): self
{
$this->setValueObject('roles', $roles);
return $this;
}
public function loadAccountField(): void
{
if (!$this->entityManager) {
throw new RuntimeException("No entity manager");
}
if ($this->get('contactId')) {
$contact = $this->entityManager->getEntityById(Contact::ENTITY_TYPE, $this->get('contactId'));
if ($contact && $contact->get('accountId')) {
$this->set('accountId', $contact->get('accountId'));
$this->set('accountName', $contact->get('accountName'));
}
}
}
public function setTitle(?string $title): self
{
$this->set('title', $title);
return $this;
}
public function getTitle(): ?string
{
return $this->get('title');
}
public function getUserName(): ?string
{
return $this->get('userName');
}
public function getAuthMethod(): ?string
{
return $this->get('authMethod');
}
public function getContactId(): ?string
{
return $this->get('contactId');
}
public function getContact(): ?Contact
{
/** @var ?Contact */
return $this->relations->getOne('contact');
}
/**
* Get a portal ID of the currently logged user.
*/
public function getPortalId(): ?string
{
return $this->get('portalId');
}
public function getAccounts(): LinkMultiple
{
/** @var LinkMultiple $value */
$value = $this->getValueObject('accounts');
return $value;
}
public function getAvatarId(): ?string
{
return $this->get('avatarId');
}
public function getAvatarColor(): ?string
{
return $this->get('avatarColor');
}
/**
* Get a password hash.
*/
public function getPassword(): string
{
return $this->get(self::FIELD_PASSWORD) ?? '';
}
/**
* @since 10.1.0
*/
public function setAuthMethod(?string $method): self
{
return $this->set(self::FIELD_AUTH_METHOD, $method);
}
/**
* @since 10.1.0
*/
public function getApiKey(): ?string
{
return $this->get(self::FIELD_API_KEY);
}
/**
* @since 10.1.0
*/
public function setApiKey(?string $apiKey): self
{
return $this->set(self::FIELD_API_KEY, $apiKey);
}
/**
* @since 10.1.0
*/
public function getSecretKey(): ?string
{
return $this->get(self::FIELD_SECRET_KEY);
}
/**
* @since 10.1.0
*/
public function setSecretKey(?string $secretKey): self
{
return $this->set(self::FIELD_SECRET_KEY, $secretKey);
}
private function getNameInternal(): ?string
{
if (!$this->hasInContainer(Field::NAME) || !$this->getFromContainer(Field::NAME)) {
if ($this->get('userName')) {
return $this->get('userName');
}
}
return $this->getFromContainer(Field::NAME);
}
private function hasNameInternal(): bool
{
if ($this->hasInContainer(Field::NAME)) {
return true;
}
if ($this->has('userName')) {
return true;
}
return false;
}
/**
* @since 10.0.0
* @internal
*/
public function getPasswordVersion(): ?int
{
return $this->get(self::FIELD_PASSWORD_VERSION);
}
/**
* @internal
* @param string[] $scopes
* @since 10.1.0
*/
public function setScopes(array $scopes): self
{
if ($this->get(self::FIELD_SCOPES) !== null) {
throw new LogicException("Scopes are already set.");
}
return $this->set(self::FIELD_SCOPES, $scopes);
}
/**
* Get access scopes. If not set, no additional restrictions.
* Only for the current user.
*
* @return ?string[]
* @since 10.1.0
*/
public function getScopes(): ?array
{
return $this->get(self::FIELD_SCOPES);
}
}