diff --git a/application/Espo/Core/Utils/SystemUser.php b/application/Espo/Core/Utils/SystemUser.php index 2bc083b590..2519b83786 100644 --- a/application/Espo/Core/Utils/SystemUser.php +++ b/application/Espo/Core/Utils/SystemUser.php @@ -42,11 +42,23 @@ class SystemUser private const ID = 'system'; private const UUID = 'ffffffff-ffff-ffff-ffff-ffffffffffff'; - private bool $isUuid; + private string $id; - public function __construct(Metadata $metadata) + public function __construct(Metadata $metadata, Config $config) { - $this->isUuid = $metadata->get(['app', 'recordId', 'dbType']) === 'uuid'; + $id = $config->get('systemUserId'); + + if ($id) { + $this->id = $id; + + return; + } + + $isUuid = $metadata->get(['app', 'recordId', 'dbType']) === 'uuid'; + + $this->id = $isUuid ? + self::UUID : + self::ID; } /** @@ -54,8 +66,6 @@ class SystemUser */ public function getId(): string { - return $this->isUuid ? - self::UUID : - self::ID; + return $this->id; } } diff --git a/application/Espo/Resources/metadata/app/config.json b/application/Espo/Resources/metadata/app/config.json index a25be59eb7..8ba2f6d649 100644 --- a/application/Espo/Resources/metadata/app/config.json +++ b/application/Espo/Resources/metadata/app/config.json @@ -13,6 +13,10 @@ "emailKeepParentTeamsEntityList" ], "params": { + "systemUserId": { + "level": "admin", + "readOnly": true + }, "smtpPassword": { "level": "internal" }, diff --git a/application/Espo/Tools/App/AppService.php b/application/Espo/Tools/App/AppService.php index 547d1b51e3..1b836d7bb0 100644 --- a/application/Espo/Tools/App/AppService.php +++ b/application/Espo/Tools/App/AppService.php @@ -30,6 +30,7 @@ namespace Espo\Tools\App; use Espo\Core\Authentication\Util\MethodProvider as AuthenticationMethodProvider; +use Espo\Core\Utils\SystemUser; use Espo\Entities\DashboardTemplate; use Espo\Entities\EmailAccount as EmailAccountEntity; use Espo\Entities\InboundEmail as InboundEmailEntity; @@ -67,7 +68,8 @@ class AppService private Preferences $preferences, private FieldUtil $fieldUtil, private Log $log, - private AuthenticationMethodProvider $authenticationMethodProvider + private AuthenticationMethodProvider $authenticationMethodProvider, + private SystemUser $systemUser ) {} /** @@ -145,6 +147,7 @@ class AppService 'timeZoneList' => $timeZoneList, 'auth2FARequired' => $auth2FARequired, 'logoutWait' => $logoutWait, + 'systemUserId' => $this->systemUser->getId(), ]; /** @var array> $map */ diff --git a/client/src/views/email/record/detail.js b/client/src/views/email/record/detail.js index 504c83e011..c5ea29e346 100644 --- a/client/src/views/email/record/detail.js +++ b/client/src/views/email/record/detail.js @@ -57,7 +57,7 @@ define('views/email/record/detail', ['views/record/detail'], function (Dep) { if (status === 'Archived') { if ( - this.model.get('createdById') === 'system' || + this.model.get('createdById') === this.getHelper().getAppParam('systemUserId') || !this.model.get('createdById') || this.model.get('isImported') ) { isRestricted = true; diff --git a/client/src/views/notification/items/base.js b/client/src/views/notification/items/base.js index 32680579ff..f9fad5e954 100644 --- a/client/src/views/notification/items/base.js +++ b/client/src/views/notification/items/base.js @@ -92,7 +92,7 @@ define('views/notification/items/base', ['view'], function (Dep) { let id = this.userId; if (this.isSystemAvatar || !id) { - id = 'system'; + id = this.getHelper().getAppParam('systemUserId'); } return this.getHelper().getAvatarHtml(id, 'small', 20); diff --git a/client/src/views/stream/note.js b/client/src/views/stream/note.js index 9879e29bef..2a9480791b 100644 --- a/client/src/views/stream/note.js +++ b/client/src/views/stream/note.js @@ -221,7 +221,7 @@ define('views/stream/note', ['view'], function (Dep) { let id = this.model.get('createdById'); if (this.isSystemAvatar) { - id = 'system'; + id = this.getHelper().getAppParam('systemUserId'); } return this.getHelper().getAvatarHtml(id, 'small', 20); diff --git a/tests/integration/Espo/Settings/AccessTest.php b/tests/integration/Espo/Settings/AccessTest.php index 3d61348230..c223295412 100644 --- a/tests/integration/Espo/Settings/AccessTest.php +++ b/tests/integration/Espo/Settings/AccessTest.php @@ -29,6 +29,7 @@ namespace tests\integration\Espo\Settings; +use Espo\Entities\User; use Espo\Tools\App\SettingsService; class AccessTest extends \tests\integration\Core\BaseTestCase @@ -98,7 +99,7 @@ class AccessTest extends \tests\integration\Core\BaseTestCase { $this->createUser([ 'userName' => 'admin-tester', - 'type' => 'admin' + 'type' => 'admin', ]); $this->auth('admin-tester'); @@ -115,4 +116,23 @@ class AccessTest extends \tests\integration\Core\BaseTestCase $this->assertTrue(property_exists($data, 'jobPeriod')); $this->assertFalse(property_exists($data, 'cryptKey')); } + + public function testReadOnly(): void + { + $this->createUser([ + 'userName' => 'admin-tester', + 'type' => User::TYPE_ADMIN, + ]); + + $this->auth('admin-tester'); + $this->setApplication($this->createApplication()); + + $this->getInjectableFactory() + ->create(SettingsService::class) + ->setConfigData((object) [ + 'systemUserId' => 'test' + ]); + + $this->assertNull($this->getConfig()->get('systemUserId')); + } }