-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IBX-6645: As the User I want to change my data and avatar in User pro…
…file (#1020)
- Loading branch information
Showing
36 changed files
with
1,273 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
* @license For full copyright and license information view LICENSE file distributed with this source code. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Ibexa\Bundle\AdminUi\Controller\User; | ||
|
||
use Ibexa\AdminUi\Specification\UserProfile\IsProfileAvailable; | ||
use Ibexa\AdminUi\UserProfile\UserProfileConfigurationInterface; | ||
use Ibexa\ContentForms\Data\Mapper\UserUpdateMapper; | ||
use Ibexa\ContentForms\Form\ActionDispatcher\ActionDispatcherInterface; | ||
use Ibexa\ContentForms\Form\Type\User\UserUpdateType; | ||
use Ibexa\ContentForms\User\View\UserUpdateView; | ||
use Ibexa\Contracts\AdminUi\Controller\Controller; | ||
use Ibexa\Contracts\ContentForms\Content\Form\Provider\GroupedContentFormFieldsProviderInterface; | ||
use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException; | ||
use Ibexa\Contracts\Core\Repository\LanguageService; | ||
use Ibexa\Contracts\Core\Repository\LocationService; | ||
use Ibexa\Contracts\Core\Repository\PermissionResolver; | ||
use Ibexa\Contracts\Core\Repository\Repository; | ||
use Ibexa\Contracts\Core\Repository\UserService; | ||
use Ibexa\Contracts\Core\Repository\Values\Content\Field; | ||
use Ibexa\Contracts\Core\Repository\Values\Content\Location; | ||
use Ibexa\Contracts\Core\Repository\Values\User\User; | ||
use Ibexa\Core\FieldType\User\Type as UserFieldType; | ||
use Symfony\Component\Form\Form; | ||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
final class ProfileEditController extends Controller | ||
{ | ||
private Repository $repository; | ||
|
||
private UserService $userService; | ||
|
||
private LocationService $locationService; | ||
|
||
private UserProfileConfigurationInterface $configuration; | ||
|
||
private PermissionResolver $permissionResolver; | ||
|
||
private LanguageService $languageService; | ||
|
||
private ActionDispatcherInterface $userActionDispatcher; | ||
|
||
private GroupedContentFormFieldsProviderInterface $groupedContentFormFieldsProvider; | ||
|
||
public function __construct( | ||
Repository $repository, | ||
UserService $userService, | ||
LocationService $locationService, | ||
UserProfileConfigurationInterface $configuration, | ||
PermissionResolver $permissionResolver, | ||
LanguageService $languageService, | ||
ActionDispatcherInterface $userActionDispatcher, | ||
GroupedContentFormFieldsProviderInterface $groupedContentFormFieldsProvider | ||
) { | ||
$this->repository = $repository; | ||
$this->userService = $userService; | ||
$this->locationService = $locationService; | ||
$this->configuration = $configuration; | ||
$this->permissionResolver = $permissionResolver; | ||
$this->languageService = $languageService; | ||
$this->userActionDispatcher = $userActionDispatcher; | ||
$this->groupedContentFormFieldsProvider = $groupedContentFormFieldsProvider; | ||
} | ||
|
||
/** | ||
* @return \Ibexa\ContentForms\User\View\UserUpdateView|\Symfony\Component\HttpFoundation\Response | ||
*/ | ||
public function editAction(Request $request, ?string $languageCode) | ||
{ | ||
$user = $this->userService->loadUser($this->permissionResolver->getCurrentUserReference()->getUserId()); | ||
if (!$this->isUserProfileAvailable($user)) { | ||
throw $this->createNotFoundException(); | ||
} | ||
|
||
if (!$this->permissionResolver->canUser('user', 'selfedit', $user)) { | ||
throw $this->createAccessDeniedException(); | ||
} | ||
|
||
$languageCode ??= $user->contentInfo->mainLanguageCode; | ||
|
||
$data = (new UserUpdateMapper())->mapToFormData($user, $user->getContentType(), [ | ||
'languageCode' => $languageCode, | ||
'filter' => static fn (Field $field): bool => $field->fieldTypeIdentifier !== UserFieldType::FIELD_TYPE_IDENTIFIER, | ||
]); | ||
|
||
$form = $this->createForm( | ||
UserUpdateType::class, | ||
$data, | ||
[ | ||
'languageCode' => $languageCode, | ||
'mainLanguageCode' => $user->contentInfo->mainLanguageCode, | ||
] | ||
); | ||
|
||
$form->handleRequest($request); | ||
if ($form->isSubmitted() && $form->isValid() && $form instanceof Form && null !== $form->getClickedButton()) { | ||
$this->userActionDispatcher->dispatchFormAction($form, $data, $form->getClickedButton()->getName()); | ||
if ($response = $this->userActionDispatcher->getResponse()) { | ||
return $response; | ||
} | ||
} | ||
|
||
$location = $this->repository->sudo( | ||
fn (): Location => $this->locationService->loadLocation( | ||
(int)$user->versionInfo->contentInfo->mainLocationId | ||
) | ||
); | ||
|
||
$parentLocation = null; | ||
try { | ||
$parentLocation = $this->locationService->loadLocation($location->parentLocationId); | ||
} catch (UnauthorizedException $e) { | ||
} | ||
|
||
return new UserUpdateView( | ||
null, | ||
[ | ||
'form' => $form->createView(), | ||
'language_code' => $languageCode, | ||
'language' => $this->languageService->loadLanguage($languageCode), | ||
'content_type' => $user->getContentType(), | ||
'user' => $user, | ||
'location' => $location, | ||
'parent_location' => $parentLocation, | ||
'grouped_fields' => $this->groupedContentFormFieldsProvider->getGroupedFields( | ||
$form->get('fieldsData')->all() | ||
), | ||
] | ||
); | ||
} | ||
|
||
private function isUserProfileAvailable(User $user): bool | ||
{ | ||
return (new IsProfileAvailable($this->configuration))->isSatisfiedBy($user); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
* @license For full copyright and license information view LICENSE file distributed with this source code. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Ibexa\Bundle\AdminUi\Controller\User; | ||
|
||
use Ibexa\AdminUi\Specification\UserProfile\IsProfileAvailable; | ||
use Ibexa\AdminUi\UserProfile\UserProfileConfigurationInterface; | ||
use Ibexa\Contracts\AdminUi\Controller\Controller; | ||
use Ibexa\Contracts\Core\Repository\PermissionResolver; | ||
use Ibexa\Contracts\Core\Repository\Repository; | ||
use Ibexa\Contracts\Core\Repository\RoleService; | ||
use Ibexa\Contracts\Core\Repository\UserService; | ||
use Ibexa\Contracts\Core\Repository\Values\User\Role; | ||
use Ibexa\Contracts\Core\Repository\Values\User\User; | ||
use Symfony\Component\HttpFoundation\Response; | ||
|
||
final class ProfileViewController extends Controller | ||
{ | ||
private Repository $repository; | ||
|
||
private UserService $userService; | ||
|
||
private RoleService $roleService; | ||
|
||
private PermissionResolver $permissionResolver; | ||
|
||
private UserProfileConfigurationInterface $configuration; | ||
|
||
public function __construct( | ||
Repository $repository, | ||
UserService $userService, | ||
RoleService $roleService, | ||
PermissionResolver $permissionResolver, | ||
UserProfileConfigurationInterface $configuration | ||
) { | ||
$this->repository = $repository; | ||
$this->userService = $userService; | ||
$this->roleService = $roleService; | ||
$this->permissionResolver = $permissionResolver; | ||
$this->configuration = $configuration; | ||
} | ||
|
||
public function viewAction(int $userId): Response | ||
{ | ||
$user = $this->userService->loadUser($userId); | ||
if (!$this->isUserProfileAvailable($user)) { | ||
throw $this->createNotFoundException(); | ||
} | ||
|
||
$canEditProfile = $this->permissionResolver->canUser('user', 'selfedit', $user); | ||
|
||
return $this->render( | ||
'@ibexadesign/account/profile/view.html.twig', | ||
[ | ||
'user' => $user, | ||
'roles' => $this->getUserRoles($user), | ||
'field_groups' => $this->configuration->getFieldGroups(), | ||
'can_edit_profile' => $canEditProfile, | ||
] | ||
); | ||
} | ||
|
||
/** | ||
* @return \Ibexa\Contracts\Core\Repository\Values\User\Role[] | ||
*/ | ||
private function getUserRoles(User $user): iterable | ||
{ | ||
if ($this->permissionResolver->hasAccess('role', 'read') !== true) { | ||
return []; | ||
} | ||
|
||
/** @var \Ibexa\Contracts\Core\Repository\Values\User\RoleAssignment[] $assignments */ | ||
$assignments = $this->repository->sudo(function () use ($user): iterable { | ||
return $this->roleService->getRoleAssignmentsForUser($user, true); | ||
}); | ||
|
||
$roles = []; | ||
foreach ($assignments as $assignment) { | ||
$role = $assignment->getRole(); | ||
if (!array_key_exists($role->id, $roles)) { | ||
$roles[$role->id] = $role; | ||
} | ||
} | ||
|
||
usort($roles, static function (Role $roleA, Role $roleB): int { | ||
return strcmp($roleA->identifier, $roleB->identifier); | ||
}); | ||
|
||
return $roles; | ||
} | ||
|
||
private function isUserProfileAvailable(User $user): bool | ||
{ | ||
return (new IsProfileAvailable($this->configuration))->isSatisfiedBy($user); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/bundle/DependencyInjection/Configuration/Parser/UserProfile.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
/** | ||
* @copyright Copyright (C) Ibexa AS. All rights reserved. | ||
* @license For full copyright and license information view LICENSE file distributed with this source code. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Ibexa\Bundle\AdminUi\DependencyInjection\Configuration\Parser; | ||
|
||
use Ibexa\Bundle\Core\DependencyInjection\Configuration\AbstractParser; | ||
use Ibexa\Bundle\Core\DependencyInjection\Configuration\SiteAccessAware\ContextualizerInterface; | ||
use Symfony\Component\Config\Definition\Builder\NodeBuilder; | ||
|
||
final class UserProfile extends AbstractParser | ||
{ | ||
public function addSemanticConfig(NodeBuilder $nodeBuilder): void | ||
{ | ||
$nodeBuilder | ||
->arrayNode('user_profile') | ||
->addDefaultsIfNotSet() | ||
->children() | ||
->booleanNode('enabled') | ||
->defaultFalse() | ||
->end() | ||
->arrayNode('content_types') | ||
->scalarPrototype()->end() | ||
->defaultValue(['editor']) | ||
->example(['editor', 'administrator']) | ||
->end() | ||
->arrayNode('field_groups') | ||
->defaultValue(['about', 'contact']) | ||
->scalarPrototype()->end() | ||
->example(['about', 'contact']) | ||
->end() | ||
->end() | ||
->end(); | ||
} | ||
|
||
/** | ||
* @param array<string, mixed> $scopeSettings | ||
* @param string $currentScope | ||
*/ | ||
public function mapConfig(array &$scopeSettings, $currentScope, ContextualizerInterface $contextualizer): void | ||
{ | ||
if (empty($scopeSettings['user_profile'])) { | ||
return; | ||
} | ||
|
||
$contextualizer->setContextualParameter( | ||
'user_profile.enabled', | ||
$currentScope, | ||
$scopeSettings['user_profile']['enabled'] | ||
); | ||
|
||
$contextualizer->setContextualParameter( | ||
'user_profiler.content_types', | ||
$currentScope, | ||
$scopeSettings['user_profile']['content_types'] | ||
); | ||
|
||
$contextualizer->setContextualParameter( | ||
'user_profile.field_groups', | ||
$currentScope, | ||
$scopeSettings['user_profile']['field_groups'] | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.