Find this useful? Enter your email to receive occasional updates for securing PHP code.
Signing you up...
Thank you for signing up!
PHP Decode
<?php declare(strict_types=1); /** * Passbolt ~ Open source password manager for teams ..
Decoded Output download
<?php
declare(strict_types=1);
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 2.13.0
*/
namespace App\Service\Groups;
use App\Error\Exception\ValidationException;
use App\Model\Dto\EntitiesChangesDto;
use App\Model\Entity\Group;
use App\Model\Entity\GroupsUser;
use App\Model\Entity\Secret;
use App\Model\Validation\GroupsUsersChange\GroupsUsersChangeValidator;
use App\Service\GroupsUsers\GroupsUsersAddService;
use App\Service\GroupsUsers\GroupsUsersDeleteService;
use App\Service\GroupsUsers\GroupsUsersUpdateService;
use App\Service\Resources\ResourcesExpireResourcesServiceInterface;
use App\Utility\UserAccessControl;
use Cake\Datasource\Exception\RecordNotFoundException;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
use Cake\Utility\Hash;
class GroupsUpdateService
{
public const UPDATE_SUCCESS_EVENT_NAME = 'GroupsUpdateController.update.success';
/**
* @var \App\Model\Table\GroupsTable
*/
private $groupsTable;
/**
* @var \App\Model\Table\GroupsUsersTable
*/
private $groupsUsersTable;
/**
* @var \App\Service\Groups\GroupGetService
*/
private $groupGetService;
/**
* @var \App\Service\GroupsUsers\GroupsUsersAddService
*/
private $groupsUsersCreateService;
/**
* @var \App\Service\GroupsUsers\GroupsUsersUpdateService
*/
private $groupsUsersUpdateService;
/**
* @var \App\Service\GroupsUsers\GroupsUsersDeleteService
*/
private $groupsUsersRemoveService;
/**
* @var \App\Service\Resources\ResourcesExpireResourcesServiceInterface
*/
private ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService;
/**
* @param \App\Service\Resources\ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService expire resource service
*/
public function __construct(
ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService
) {
$this->resourcesExpireResourcesService = $resourcesExpireResourcesService;
$this->groupsTable = TableRegistry::getTableLocator()->get('Groups');
$this->groupsUsersTable = TableRegistry::getTableLocator()->get('GroupsUsers');
$this->groupGetService = new GroupGetService();
$this->groupsUsersCreateService = new GroupsUsersAddService();
$this->groupsUsersUpdateService = new GroupsUsersUpdateService();
$this->groupsUsersRemoveService = new GroupsUsersDeleteService();
}
/**
* Update a group.
*
* @note if the operator is not a group manager, requested additions will be ignored.
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param string $groupId The identified of the group to update
* @param array $metaData The group meta data to update
* @param array|null $changes The list of group users changes to apply
* [
* [
* string $id The group user identifier (Required for delete an update scenarios)
* string $user_id The user identifier (Required for add scenarios)
* string $is_admin Is the user group manager (Required for add and update scenarios)
* bool $delete Should delete the group user (Required for delete scenarios)
* ],
* ...
* ]
* @param array|null $secrets The list of new secrets to add
* [
* [
* string $user_id The user identifier
* string $resource_id The resource identifier
* string $data The encrypted secret
* ],
* ...
* ]
* @return \App\Model\Dto\EntitiesChangesDto
* @throws \Exception If an unexpected error occurred.
*/
public function update(
UserAccessControl $uac,
string $groupId,
array $metaData,
?array $changes = [],
?array $secrets = []
): EntitiesChangesDto {
$group = $this->groupGetService->getNotDeletedOrFail($groupId);
$this->assertChanges($group, $changes);
$entitiesChangesDto = new EntitiesChangesDto();
$this->groupsTable->getConnection()->transactional(
function () use ($uac, $group, $metaData, $changes, $secrets, $entitiesChangesDto) {
$this->updateMetaData($uac, $group, $metaData);
$entitiesChangesDto->pushUpdatedEntity($group);
$entitiesChangesDto->merge($this->addGroupsUsers($uac, $group, $changes, $secrets));
$entitiesChangesDto->merge($this->updateGroupsUsers($uac, $group, $changes));
$entitiesChangesDto->merge($this->deleteGroupsUsers($uac, $group, $changes));
$this->resourcesExpireResourcesService->expireResourcesForSecrets(
$entitiesChangesDto->getDeletedEntities(Secret::class)
);
$this->notifyUsers($uac, $group, $entitiesChangesDto);
}
);
return $entitiesChangesDto;
}
/**
* Assert the list of changes.
*
* @param \App\Model\Entity\Group $group The group to update
* @param array $changes The list of group users changes to apply
* @return void
*/
private function assertChanges(Group $group, array $changes): void
{
$validator = new GroupsUsersChangeValidator();
foreach ($changes as $rowIndexRef => $change) {
$errors = $validator->validate($change);
if (!empty($errors)) {
$group->setError('groups_users', [$rowIndexRef => $errors]);
$this->handleValidationErrors($group);
}
}
}
/**
* Update the group meta data.
*
* @param \App\Utility\UserAccessControl $uac The operator
* @param \App\Model\Entity\Group $group The target group
* @param array $metaData The raw meta data to update
* @return void
*/
private function updateMetaData(UserAccessControl $uac, Group $group, array $metaData): void
{
if (!$uac->isAdmin() || empty($metaData)) {
return;
}
$groupPatchOptions = [
'accessibleFields' => [
'name' => true,
'modified_by' => true,
],
];
$metaData['modified_by'] = $uac->getId();
$this->groupsTable->patchEntity($group, $metaData, $groupPatchOptions);
$this->groupsTable->save($group);
if ($group->hasErrors()) {
$this->handleValidationErrors($group);
}
}
/**
* Handle group validation errors.
*
* @param \App\Model\Entity\Group $group The target group
* @throws \App\Error\Exception\ValidationException If the group has errors.
* @return void
*/
private function handleValidationErrors(Group $group): void
{
$msg = __('Could not validate group data.');
throw new ValidationException($msg, $group, $this->groupsTable);
}
/**
* Add groups users.
*
* @note if the operator is not a group manager, requested additions will be ignored.
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $changes The list of group users changes.
* @param array $secretsData The list of secrets to add.
* @return \App\Model\Dto\EntitiesChangesDto Entities changes applied following the addition of users to groups
* @throws \Exception If an unexpected error occurred.
*/
private function addGroupsUsers(
UserAccessControl $uac,
Group $group,
array $changes,
array $secretsData
): EntitiesChangesDto {
$entitiesChangesDto = new EntitiesChangesDto();
$isUacManager = $this->groupsUsersTable->isManager($uac->getId(), $group->id);
if (!$isUacManager) {
return $entitiesChangesDto;
}
foreach ($changes as $rowIndexRef => $groupUserData) {
if (GroupsUsersChangeValidator::isAddChange($groupUserData)) {
$addedGroupsUserEntitiesChangesDto = $this->addGroupUser(
$uac,
$group,
$groupUserData,
$secretsData,
$rowIndexRef
);
$entitiesChangesDto->merge($addedGroupsUserEntitiesChangesDto);
}
}
return $entitiesChangesDto;
}
/**
* Add a group user.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to add.
* @param array $secretsData The data of the secrets to add.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return \App\Model\Dto\EntitiesChangesDto Entities changes applied following the addition of the user to group
* @throws \App\Error\Exception\ValidationException If a validation error occured while inserting the new group user.
* @throws \Exception If an unexpected error occurred.
*/
private function addGroupUser(
UserAccessControl $uac,
Group $group,
array $groupUserData,
array $secretsData,
int $rowIndexRef
): EntitiesChangesDto {
$userId = Hash::get($groupUserData, 'user_id');
$groupUserData['group_id'] = $group->id;
$userSecretsData = Hash::extract($secretsData, "{n}[user_id={$userId}]");
$dto = new EntitiesChangesDto();
try {
$dto = $this->groupsUsersCreateService->add($uac, $groupUserData, $userSecretsData);
} catch (ValidationException $e) {
$group->setError('groups_users', [$rowIndexRef => $e->getErrors()]);
$this->handleValidationErrors($group);
}
return $dto;
}
/**
* Update groups users.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $changes The list of group users changes.
* @return \App\Model\Dto\EntitiesChangesDto Array of updated GroupUser
*/
private function updateGroupsUsers(UserAccessControl $uac, Group $group, array $changes): EntitiesChangesDto
{
$entitiesChangesDto = new EntitiesChangesDto();
$updateGroupsUsersChanges = [];
// Extract groups users update changes.
foreach ($changes as $rowIndexRef => $change) {
if (GroupsUsersChangeValidator::isUpdateChange($change)) {
// Preserve the changes index for later associated error treatment.
$updateGroupsUsersChanges[$rowIndexRef] = $change;
}
}
/*
* Sort the changes to execute "add manager" update operations first. Each update operation of the group will
* check if there is a group manager, therefore sort the changes in order to get changes that grant the manager role
* on top of the list.
* Preserve the changes index for later associated error treatment.
*/
$this->sortGroupUsersUpdateChanges($updateGroupsUsersChanges);
foreach ($updateGroupsUsersChanges as $rowIndexRef => $updateGroupsUsersChange) {
$groupUser = $this->updateGroupUser($uac, $group, $updateGroupsUsersChange, $rowIndexRef);
$entitiesChangesDto->pushUpdatedEntity($groupUser);
}
return $entitiesChangesDto;
}
/**
* Sort the list of groups users update change to get on top groups users change that grant the manager role.
*
* @param array $updateGroupsUsersChanges The groups users update changes.
* @return void
*/
private function sortGroupUsersUpdateChanges(array &$updateGroupsUsersChanges): void
{
uasort($updateGroupsUsersChanges, function (array $groupUserChangeA, array $groupUserChangeB) {
$changeAIsAdmin = Hash::get($groupUserChangeA, 'is_admin');
$changeBIsAdmin = Hash::get($groupUserChangeB, 'is_admin');
if ($changeAIsAdmin) {
return -1;
} elseif ($changeBIsAdmin) {
return 1;
}
return 0;
});
}
/**
* Update a group user.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to update.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return ?\App\Model\Entity\GroupsUser
*/
private function updateGroupUser(
UserAccessControl $uac,
Group $group,
array $groupUserData,
int $rowIndexRef
): ?GroupsUser {
$groupUserToUpdate = $this->getAndAssertGroupUserFromData($group, $groupUserData, $rowIndexRef);
// Return if there is no group role change requested.
$isAdmin = Hash::get($groupUserData, 'is_admin');
if ($groupUserToUpdate->is_admin === $isAdmin) {
return null;
}
try {
return $this->groupsUsersUpdateService->update($uac, $groupUserToUpdate->id, $groupUserData);
} catch (ValidationException $e) {
$group->setError('groups_users', [$rowIndexRef => $e->getErrors() ?? $e->getMessage()]);
$this->handleValidationErrors($group);
} catch (RecordNotFoundException $e) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => ['Cannot find the group user.']]]]);
$this->handleValidationErrors($group);
}
return null;
}
/**
* Get and assert group user from group user data
*
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to update or delete.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return \App\Model\Entity\GroupsUser
*/
private function getAndAssertGroupUserFromData(Group $group, array $groupUserData, int $rowIndexRef): GroupsUser
{
$groupUserId = Hash::get($groupUserData, 'id');
try {
$groupUser = $this->groupsUsersTable->get($groupUserId);
} catch (RecordNotFoundException $e) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => 'Cannot find the group user.']]]);
$this->handleValidationErrors($group);
}
if ($groupUser->group_id !== $group->id) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => 'Cannot find the group user.']]]);
$this->handleValidationErrors($group);
}
return $groupUser;
}
/**
* Delete groups users.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $changes The list of group users changes.
* @return \App\Model\Dto\EntitiesChangesDto
*/
private function deleteGroupsUsers(UserAccessControl $uac, Group $group, array $changes): EntitiesChangesDto
{
$entitiesChangesDto = new EntitiesChangesDto();
foreach ($changes as $rowIndexRef => $change) {
if (GroupsUsersChangeValidator::isDeleteChange($change)) {
$deletedGroupUserEntitiesChangesDto = $this->deleteGroupUser($uac, $group, $change, $rowIndexRef);
$entitiesChangesDto->merge($deletedGroupUserEntitiesChangesDto);
}
}
return $entitiesChangesDto;
}
/**
* Delete a group user
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to delete.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return \App\Model\Dto\EntitiesChangesDto
* @throws \Exception
*/
private function deleteGroupUser(
UserAccessControl $uac,
Group $group,
array $groupUserData,
int $rowIndexRef
): EntitiesChangesDto {
$groupUser = $this->getAndAssertGroupUserFromData($group, $groupUserData, $rowIndexRef);
$dto = new EntitiesChangesDto();
try {
$dto = $this->groupsUsersRemoveService->delete($uac, $groupUser->id);
} catch (ValidationException $e) {
$group->setError('groups_users', [$rowIndexRef => $e->getErrors() ?? $e->getMessage()]);
$this->handleValidationErrors($group);
} catch (RecordNotFoundException $e) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => ['Cannot find the group user.']]]]);
$this->handleValidationErrors($group);
}
return $dto;
}
/**
* Notify the users that they group have been deleted
*
* @param \App\Utility\UserAccessControl $uac The current user
* @param \App\Model\Entity\Group $group The updated group
* @param \App\Model\Dto\EntitiesChangesDto $entitiesChanges the list of added groups users
* @return void
*/
private function notifyUsers(
UserAccessControl $uac,
Group $group,
EntitiesChangesDto $entitiesChanges
): void {
$event = new Event(static::UPDATE_SUCCESS_EVENT_NAME, $this, [
'group' => $group,
'entitiesChanges' => $entitiesChanges,
'userId' => $uac->getId(),
]);
$this->groupsTable->getEventManager()->dispatch($event);
}
}
?>
Did this file decode correctly?
Original Code
<?php
declare(strict_types=1);
/**
* Passbolt ~ Open source password manager for teams
* Copyright (c) Passbolt SA (https://www.passbolt.com)
*
* Licensed under GNU Affero General Public License version 3 of the or any later version.
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Passbolt SA (https://www.passbolt.com)
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
* @link https://www.passbolt.com Passbolt(tm)
* @since 2.13.0
*/
namespace App\Service\Groups;
use App\Error\Exception\ValidationException;
use App\Model\Dto\EntitiesChangesDto;
use App\Model\Entity\Group;
use App\Model\Entity\GroupsUser;
use App\Model\Entity\Secret;
use App\Model\Validation\GroupsUsersChange\GroupsUsersChangeValidator;
use App\Service\GroupsUsers\GroupsUsersAddService;
use App\Service\GroupsUsers\GroupsUsersDeleteService;
use App\Service\GroupsUsers\GroupsUsersUpdateService;
use App\Service\Resources\ResourcesExpireResourcesServiceInterface;
use App\Utility\UserAccessControl;
use Cake\Datasource\Exception\RecordNotFoundException;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
use Cake\Utility\Hash;
class GroupsUpdateService
{
public const UPDATE_SUCCESS_EVENT_NAME = 'GroupsUpdateController.update.success';
/**
* @var \App\Model\Table\GroupsTable
*/
private $groupsTable;
/**
* @var \App\Model\Table\GroupsUsersTable
*/
private $groupsUsersTable;
/**
* @var \App\Service\Groups\GroupGetService
*/
private $groupGetService;
/**
* @var \App\Service\GroupsUsers\GroupsUsersAddService
*/
private $groupsUsersCreateService;
/**
* @var \App\Service\GroupsUsers\GroupsUsersUpdateService
*/
private $groupsUsersUpdateService;
/**
* @var \App\Service\GroupsUsers\GroupsUsersDeleteService
*/
private $groupsUsersRemoveService;
/**
* @var \App\Service\Resources\ResourcesExpireResourcesServiceInterface
*/
private ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService;
/**
* @param \App\Service\Resources\ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService expire resource service
*/
public function __construct(
ResourcesExpireResourcesServiceInterface $resourcesExpireResourcesService
) {
$this->resourcesExpireResourcesService = $resourcesExpireResourcesService;
$this->groupsTable = TableRegistry::getTableLocator()->get('Groups');
$this->groupsUsersTable = TableRegistry::getTableLocator()->get('GroupsUsers');
$this->groupGetService = new GroupGetService();
$this->groupsUsersCreateService = new GroupsUsersAddService();
$this->groupsUsersUpdateService = new GroupsUsersUpdateService();
$this->groupsUsersRemoveService = new GroupsUsersDeleteService();
}
/**
* Update a group.
*
* @note if the operator is not a group manager, requested additions will be ignored.
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param string $groupId The identified of the group to update
* @param array $metaData The group meta data to update
* @param array|null $changes The list of group users changes to apply
* [
* [
* string $id The group user identifier (Required for delete an update scenarios)
* string $user_id The user identifier (Required for add scenarios)
* string $is_admin Is the user group manager (Required for add and update scenarios)
* bool $delete Should delete the group user (Required for delete scenarios)
* ],
* ...
* ]
* @param array|null $secrets The list of new secrets to add
* [
* [
* string $user_id The user identifier
* string $resource_id The resource identifier
* string $data The encrypted secret
* ],
* ...
* ]
* @return \App\Model\Dto\EntitiesChangesDto
* @throws \Exception If an unexpected error occurred.
*/
public function update(
UserAccessControl $uac,
string $groupId,
array $metaData,
?array $changes = [],
?array $secrets = []
): EntitiesChangesDto {
$group = $this->groupGetService->getNotDeletedOrFail($groupId);
$this->assertChanges($group, $changes);
$entitiesChangesDto = new EntitiesChangesDto();
$this->groupsTable->getConnection()->transactional(
function () use ($uac, $group, $metaData, $changes, $secrets, $entitiesChangesDto) {
$this->updateMetaData($uac, $group, $metaData);
$entitiesChangesDto->pushUpdatedEntity($group);
$entitiesChangesDto->merge($this->addGroupsUsers($uac, $group, $changes, $secrets));
$entitiesChangesDto->merge($this->updateGroupsUsers($uac, $group, $changes));
$entitiesChangesDto->merge($this->deleteGroupsUsers($uac, $group, $changes));
$this->resourcesExpireResourcesService->expireResourcesForSecrets(
$entitiesChangesDto->getDeletedEntities(Secret::class)
);
$this->notifyUsers($uac, $group, $entitiesChangesDto);
}
);
return $entitiesChangesDto;
}
/**
* Assert the list of changes.
*
* @param \App\Model\Entity\Group $group The group to update
* @param array $changes The list of group users changes to apply
* @return void
*/
private function assertChanges(Group $group, array $changes): void
{
$validator = new GroupsUsersChangeValidator();
foreach ($changes as $rowIndexRef => $change) {
$errors = $validator->validate($change);
if (!empty($errors)) {
$group->setError('groups_users', [$rowIndexRef => $errors]);
$this->handleValidationErrors($group);
}
}
}
/**
* Update the group meta data.
*
* @param \App\Utility\UserAccessControl $uac The operator
* @param \App\Model\Entity\Group $group The target group
* @param array $metaData The raw meta data to update
* @return void
*/
private function updateMetaData(UserAccessControl $uac, Group $group, array $metaData): void
{
if (!$uac->isAdmin() || empty($metaData)) {
return;
}
$groupPatchOptions = [
'accessibleFields' => [
'name' => true,
'modified_by' => true,
],
];
$metaData['modified_by'] = $uac->getId();
$this->groupsTable->patchEntity($group, $metaData, $groupPatchOptions);
$this->groupsTable->save($group);
if ($group->hasErrors()) {
$this->handleValidationErrors($group);
}
}
/**
* Handle group validation errors.
*
* @param \App\Model\Entity\Group $group The target group
* @throws \App\Error\Exception\ValidationException If the group has errors.
* @return void
*/
private function handleValidationErrors(Group $group): void
{
$msg = __('Could not validate group data.');
throw new ValidationException($msg, $group, $this->groupsTable);
}
/**
* Add groups users.
*
* @note if the operator is not a group manager, requested additions will be ignored.
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $changes The list of group users changes.
* @param array $secretsData The list of secrets to add.
* @return \App\Model\Dto\EntitiesChangesDto Entities changes applied following the addition of users to groups
* @throws \Exception If an unexpected error occurred.
*/
private function addGroupsUsers(
UserAccessControl $uac,
Group $group,
array $changes,
array $secretsData
): EntitiesChangesDto {
$entitiesChangesDto = new EntitiesChangesDto();
$isUacManager = $this->groupsUsersTable->isManager($uac->getId(), $group->id);
if (!$isUacManager) {
return $entitiesChangesDto;
}
foreach ($changes as $rowIndexRef => $groupUserData) {
if (GroupsUsersChangeValidator::isAddChange($groupUserData)) {
$addedGroupsUserEntitiesChangesDto = $this->addGroupUser(
$uac,
$group,
$groupUserData,
$secretsData,
$rowIndexRef
);
$entitiesChangesDto->merge($addedGroupsUserEntitiesChangesDto);
}
}
return $entitiesChangesDto;
}
/**
* Add a group user.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to add.
* @param array $secretsData The data of the secrets to add.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return \App\Model\Dto\EntitiesChangesDto Entities changes applied following the addition of the user to group
* @throws \App\Error\Exception\ValidationException If a validation error occured while inserting the new group user.
* @throws \Exception If an unexpected error occurred.
*/
private function addGroupUser(
UserAccessControl $uac,
Group $group,
array $groupUserData,
array $secretsData,
int $rowIndexRef
): EntitiesChangesDto {
$userId = Hash::get($groupUserData, 'user_id');
$groupUserData['group_id'] = $group->id;
$userSecretsData = Hash::extract($secretsData, "{n}[user_id={$userId}]");
$dto = new EntitiesChangesDto();
try {
$dto = $this->groupsUsersCreateService->add($uac, $groupUserData, $userSecretsData);
} catch (ValidationException $e) {
$group->setError('groups_users', [$rowIndexRef => $e->getErrors()]);
$this->handleValidationErrors($group);
}
return $dto;
}
/**
* Update groups users.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $changes The list of group users changes.
* @return \App\Model\Dto\EntitiesChangesDto Array of updated GroupUser
*/
private function updateGroupsUsers(UserAccessControl $uac, Group $group, array $changes): EntitiesChangesDto
{
$entitiesChangesDto = new EntitiesChangesDto();
$updateGroupsUsersChanges = [];
// Extract groups users update changes.
foreach ($changes as $rowIndexRef => $change) {
if (GroupsUsersChangeValidator::isUpdateChange($change)) {
// Preserve the changes index for later associated error treatment.
$updateGroupsUsersChanges[$rowIndexRef] = $change;
}
}
/*
* Sort the changes to execute "add manager" update operations first. Each update operation of the group will
* check if there is a group manager, therefore sort the changes in order to get changes that grant the manager role
* on top of the list.
* Preserve the changes index for later associated error treatment.
*/
$this->sortGroupUsersUpdateChanges($updateGroupsUsersChanges);
foreach ($updateGroupsUsersChanges as $rowIndexRef => $updateGroupsUsersChange) {
$groupUser = $this->updateGroupUser($uac, $group, $updateGroupsUsersChange, $rowIndexRef);
$entitiesChangesDto->pushUpdatedEntity($groupUser);
}
return $entitiesChangesDto;
}
/**
* Sort the list of groups users update change to get on top groups users change that grant the manager role.
*
* @param array $updateGroupsUsersChanges The groups users update changes.
* @return void
*/
private function sortGroupUsersUpdateChanges(array &$updateGroupsUsersChanges): void
{
uasort($updateGroupsUsersChanges, function (array $groupUserChangeA, array $groupUserChangeB) {
$changeAIsAdmin = Hash::get($groupUserChangeA, 'is_admin');
$changeBIsAdmin = Hash::get($groupUserChangeB, 'is_admin');
if ($changeAIsAdmin) {
return -1;
} elseif ($changeBIsAdmin) {
return 1;
}
return 0;
});
}
/**
* Update a group user.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to update.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return ?\App\Model\Entity\GroupsUser
*/
private function updateGroupUser(
UserAccessControl $uac,
Group $group,
array $groupUserData,
int $rowIndexRef
): ?GroupsUser {
$groupUserToUpdate = $this->getAndAssertGroupUserFromData($group, $groupUserData, $rowIndexRef);
// Return if there is no group role change requested.
$isAdmin = Hash::get($groupUserData, 'is_admin');
if ($groupUserToUpdate->is_admin === $isAdmin) {
return null;
}
try {
return $this->groupsUsersUpdateService->update($uac, $groupUserToUpdate->id, $groupUserData);
} catch (ValidationException $e) {
$group->setError('groups_users', [$rowIndexRef => $e->getErrors() ?? $e->getMessage()]);
$this->handleValidationErrors($group);
} catch (RecordNotFoundException $e) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => ['Cannot find the group user.']]]]);
$this->handleValidationErrors($group);
}
return null;
}
/**
* Get and assert group user from group user data
*
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to update or delete.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return \App\Model\Entity\GroupsUser
*/
private function getAndAssertGroupUserFromData(Group $group, array $groupUserData, int $rowIndexRef): GroupsUser
{
$groupUserId = Hash::get($groupUserData, 'id');
try {
$groupUser = $this->groupsUsersTable->get($groupUserId);
} catch (RecordNotFoundException $e) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => 'Cannot find the group user.']]]);
$this->handleValidationErrors($group);
}
if ($groupUser->group_id !== $group->id) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => 'Cannot find the group user.']]]);
$this->handleValidationErrors($group);
}
return $groupUser;
}
/**
* Delete groups users.
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $changes The list of group users changes.
* @return \App\Model\Dto\EntitiesChangesDto
*/
private function deleteGroupsUsers(UserAccessControl $uac, Group $group, array $changes): EntitiesChangesDto
{
$entitiesChangesDto = new EntitiesChangesDto();
foreach ($changes as $rowIndexRef => $change) {
if (GroupsUsersChangeValidator::isDeleteChange($change)) {
$deletedGroupUserEntitiesChangesDto = $this->deleteGroupUser($uac, $group, $change, $rowIndexRef);
$entitiesChangesDto->merge($deletedGroupUserEntitiesChangesDto);
}
}
return $entitiesChangesDto;
}
/**
* Delete a group user
*
* @param \App\Utility\UserAccessControl $uac The user at the origin of the operation
* @param \App\Model\Entity\Group $group The group to update.
* @param array $groupUserData The data of the group user to delete.
* @param int $rowIndexRef The index of the treated group user in the request data, for error purpose.
* @return \App\Model\Dto\EntitiesChangesDto
* @throws \Exception
*/
private function deleteGroupUser(
UserAccessControl $uac,
Group $group,
array $groupUserData,
int $rowIndexRef
): EntitiesChangesDto {
$groupUser = $this->getAndAssertGroupUserFromData($group, $groupUserData, $rowIndexRef);
$dto = new EntitiesChangesDto();
try {
$dto = $this->groupsUsersRemoveService->delete($uac, $groupUser->id);
} catch (ValidationException $e) {
$group->setError('groups_users', [$rowIndexRef => $e->getErrors() ?? $e->getMessage()]);
$this->handleValidationErrors($group);
} catch (RecordNotFoundException $e) {
$group->setError('groups_users', [$rowIndexRef => ['id' => ['exists' => ['Cannot find the group user.']]]]);
$this->handleValidationErrors($group);
}
return $dto;
}
/**
* Notify the users that they group have been deleted
*
* @param \App\Utility\UserAccessControl $uac The current user
* @param \App\Model\Entity\Group $group The updated group
* @param \App\Model\Dto\EntitiesChangesDto $entitiesChanges the list of added groups users
* @return void
*/
private function notifyUsers(
UserAccessControl $uac,
Group $group,
EntitiesChangesDto $entitiesChanges
): void {
$event = new Event(static::UPDATE_SUCCESS_EVENT_NAME, $this, [
'group' => $group,
'entitiesChanges' => $entitiesChanges,
'userId' => $uac->getId(),
]);
$this->groupsTable->getEventManager()->dispatch($event);
}
}
Function Calls
None |
Stats
MD5 | 05acde79ea527f5c976ea9fcf220a611 |
Eval Count | 0 |
Decode Time | 115 ms |