<?php
namespace App\Security\Voters;
use App\Entity\Account;
use App\Entity\Client;
use App\Entity\OA2User;
use App\Repository\ClientAccountRepository;
use App\Repository\ClientRepository;
use App\Repository\Permissions\AccountPermissionSettingRepository;
use App\Repository\Permissions\ClientAccountPermissionRepository;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class AccountVoter extends Voter
{
public const MODE_READ = 'read';
public const MODE_UPDATE = 'update';
public const MODE_DELETE = 'delete';
public const PERMISSION_VIEW_ACCOUNT = 'view_account';
public const PERMISSION_INTERNAL_PAYMENT = 'create_internal_payment';
public const PERMISSION_SIGN_TRANSACTION = 'sign_transactions';
public const PERMISSION_SEPA_PAYMENT = 'create_sepa_payment';
public const PERMISSION_EXCHANGE_CURRENCY = 'exchange_currency';
/**
* @var ClientRepository
*/
private $clientRepository;
/**
* @var ClientAccountRepository
*/
private $clientAccountRepository;
/**
* @var ClientAccountPermissionRepository
*/
private $clientAccPermRepository;
/**
* @var AccountPermissionSettingRepository
*/
private $accPermSettingRepository;
public function __construct(
ClientRepository $clientRepository,
AccountPermissionSettingRepository $permissionSettingRepository,
ClientAccountPermissionRepository $accountPermissionRepository,
ClientAccountRepository $clientAccountRepository
) {
$this->clientRepository = $clientRepository;
$this->accPermSettingRepository = $permissionSettingRepository;
$this->clientAccPermRepository = $accountPermissionRepository;
$this->clientAccountRepository = $clientAccountRepository;
}
protected function supports($attribute, $subject)
{
if (!in_array($attribute, $this->getSupportedPermissions())) {
return false;
}
return !(!$subject instanceof Account)
;
}
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
if (!in_array($attribute, $this->getSupportedPermissions())) {
return false;
}
/** @var Account $account */
$account = $subject;
$currentClient = $this->getCurrentClient($token);
if (!$currentClient) {
return false;
}
if ($account->getClient()->getId() === $currentClient->getId()) {
return true;
}
switch ($attribute) {
case self::PERMISSION_VIEW_ACCOUNT:
return $this->canViewAccount($account, $currentClient);
break;
case self::PERMISSION_INTERNAL_PAYMENT:
return $this->canInternalPayment($account, $currentClient);
break;
case self::PERMISSION_SIGN_TRANSACTION:
return $this->canSignTransactio($account, $currentClient);
break;
case self::PERMISSION_SEPA_PAYMENT:
return $this->canSepaPayment($account, $currentClient);
break;
case self::PERMISSION_EXCHANGE_CURRENCY:
return $this->canExchangeCurrency($account, $currentClient);
break;
default:
break;
}
// TODO: check owner rules!
$relationAccount = $this->clientAccountRepository->findOneByPersonalAccount($currentClient, $account);
return (bool) ($relationAccount)
;
}
private function canViewAccount(Account $account, Client $currentClient): bool
{
$permissionId = $this->accPermSettingRepository->getIdByHardvalue(self::PERMISSION_VIEW_ACCOUNT);
$permission = $this->clientAccPermRepository->findOneByPermission($account, $currentClient, $permissionId);
return $permission ? true : false;
}
private function canInternalPayment(Account $account, Client $currentClient): bool
{
$permissionId = $this->accPermSettingRepository->getIdByHardvalue(self::PERMISSION_INTERNAL_PAYMENT);
$permission = $this->clientAccPermRepository->findOneByPermission($account, $currentClient, $permissionId);
return $permission ? true : false;
}
private function canSignTransactio(Account $account, Client $currentClient): bool
{
$permissionId = $this->accPermSettingRepository->getIdByHardvalue(self::PERMISSION_SIGN_TRANSACTION);
$permission = $this->clientAccPermRepository->findOneByPermission($account, $currentClient, $permissionId);
return $permission ? true : false;
}
private function canSepaPayment(Account $account, Client $currentClient): bool
{
$permissionId = $this->accPermSettingRepository->getIdByHardvalue(self::PERMISSION_SEPA_PAYMENT);
$permission = $this->clientAccPermRepository->findOneByPermission($account, $currentClient, $permissionId);
return $permission ? true : false;
}
private function canExchangeCurrency(Account $account, Client $currentClient): bool
{
$permissionId = $this->accPermSettingRepository->getIdByHardvalue(self::PERMISSION_EXCHANGE_CURRENCY);
$permission = $this->clientAccPermRepository->findOneByPermission($account, $currentClient, $permissionId);
return $permission ? true : false;
}
private function getSupportedPermissions(): array
{
return [
self::MODE_READ, self::MODE_UPDATE, self::MODE_DELETE,
self::PERMISSION_VIEW_ACCOUNT,
self::PERMISSION_INTERNAL_PAYMENT,
self::PERMISSION_SIGN_TRANSACTION,
self::PERMISSION_SEPA_PAYMENT,
self::PERMISSION_EXCHANGE_CURRENCY,
];
}
private function getCurrentClient(TokenInterface $token): ?Client
{
/** @var OA2User $oa2User */
$oa2User = $token->getUser();
if (!$oa2User instanceof OA2User || $oa2User->isBankUser()) {
return null; // Client user only
}
return $this->clientRepository->findOneByOa2User($oa2User);
}
}