Extracts the user profile read-view into a core service + shared partial so
modules no longer duplicate the assignment/scope logic, and migrates the
admin/users list as the drawer's second consumer.
Consolidation:
- `core/Service/User/UserProfileViewService` owns the single read-path that
resolves tenants/departments/roles for a user UUID, enforces scope-aware
department visibility, and returns a consistent `{status, user}` shape.
- `templates/partials/app-user-profile.phtml` is the shared render template;
takes `$profileKey` for storage namespace + lightbox grouping.
- `AddressBookService::buildViewContext()` shrinks to a one-line delegation
and drops its `UserAssignmentService` dependency. The old
`modules/addressbook/templates/address-book-profile.phtml` is removed.
admin/users migration:
- `pages/admin/users/view-fragment($id).php` + `(none).phtml` use the core
service and enforce `ABILITY_ADMIN_USERS_VIEW`.
- `admin-users-index.js` replaces the grid-native `linkColumn` on the first
name with a formatter that emits `data-drawer-trigger`; `linkColumn` is
disabled so the drawer click handler wins. `fullUrl` points at the edit
form — drawer → edit is one click.
- Drawer labels wired via page config.
The new `DetailDrawerFragmentContractTest` validated the users fragment
endpoint automatically — no manual test additions were needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.1 KiB
PHP
90 lines
3.1 KiB
PHP
<?php
|
|
|
|
namespace MintyPHP\Tests\Module\AddressBook\Service;
|
|
|
|
use MintyPHP\Module\AddressBook\Service\AddressBookService;
|
|
use MintyPHP\Service\Access\RoleService;
|
|
use MintyPHP\Service\CustomField\UserCustomFieldValueService;
|
|
use MintyPHP\Service\Org\DepartmentService;
|
|
use MintyPHP\Service\Tenant\TenantScopeService;
|
|
use MintyPHP\Service\Tenant\TenantService;
|
|
use MintyPHP\Service\User\UserAccountService;
|
|
use MintyPHP\Service\User\UserAvatarService;
|
|
use MintyPHP\Service\User\UserProfileViewService;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class AddressBookServiceTest extends TestCase
|
|
{
|
|
public function testBuildIndexContextBuildsTenantDepartmentMapForGlobalScope(): void
|
|
{
|
|
$userAccountService = $this->createMock(UserAccountService::class);
|
|
$tenantService = $this->createMock(TenantService::class);
|
|
$departmentService = $this->createMock(DepartmentService::class);
|
|
$roleService = $this->createMock(RoleService::class);
|
|
$scopeGateway = $this->createMock(TenantScopeService::class);
|
|
$customFieldGateway = $this->createMock(UserCustomFieldValueService::class);
|
|
$avatarService = $this->createMock(UserAvatarService::class);
|
|
$userProfileViewService = $this->createMock(UserProfileViewService::class);
|
|
|
|
$scopeGateway
|
|
->expects($this->once())
|
|
->method('getUserTenantIds')
|
|
->with(7)
|
|
->willReturn([]);
|
|
$tenantService
|
|
->expects($this->once())
|
|
->method('list')
|
|
->willReturn([
|
|
['id' => 1, 'uuid' => 'tenant-a', 'description' => 'Tenant A'],
|
|
['id' => 2, 'uuid' => 'tenant-b', 'description' => 'Tenant B'],
|
|
]);
|
|
$scopeGateway
|
|
->expects($this->exactly(2))
|
|
->method('isStrict')
|
|
->willReturn(false);
|
|
$departmentService
|
|
->expects($this->once())
|
|
->method('list')
|
|
->willReturn([
|
|
['id' => 10, 'tenant_id' => 1, 'description' => 'Sales'],
|
|
['id' => 20, 'tenant_id' => 2, 'description' => 'Support'],
|
|
]);
|
|
$departmentService
|
|
->expects($this->never())
|
|
->method('listByTenantIds');
|
|
$roleService
|
|
->expects($this->once())
|
|
->method('listActive')
|
|
->willReturn([]);
|
|
|
|
$customFieldGateway
|
|
->expects($this->once())
|
|
->method('extractCustomFieldFilterSpec')
|
|
->with([], 7)
|
|
->willReturn([
|
|
'definitions' => [],
|
|
'query' => [],
|
|
]);
|
|
$service = new AddressBookService(
|
|
$userAccountService,
|
|
$tenantService,
|
|
$departmentService,
|
|
$roleService,
|
|
$scopeGateway,
|
|
$customFieldGateway,
|
|
$avatarService,
|
|
$userProfileViewService
|
|
);
|
|
|
|
$context = $service->buildIndexContext(7, []);
|
|
|
|
$this->assertSame(
|
|
[
|
|
'tenant-a' => ['10'],
|
|
'tenant-b' => ['20'],
|
|
],
|
|
$context['tenantDepartmentMap']
|
|
);
|
|
}
|
|
}
|