<?php
/**
* User: broasca
* Date: 06.05.2021
* Time: 16:07
*/
namespace App\EventListener;
use App\Entity\ApiLog;
use App\Repository\ApiUsageRepository;
use App\Repository\UserRepository;
use App\Service\AbstractEntityService;
use App\Service\UserService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Contracts\Translation\TranslatorInterface;
class ResponseListener
{
/**
* @var EntityManagerInterface
*/
protected $entityManager;
/**
* @var AbstractEntityService
*/
protected $abstractEntityService;
/**
* @var UserRepository
*/
protected $userRepository;
/**
* @var ApiUsageRepository
*/
protected $apiUsageRepository;
/**
* @var TranslatorInterface
*/
protected $translator;
/**
* @var UserService
*/
protected $userService;
public function __construct(
EntityManagerInterface $entityManager,
AbstractEntityService $abstractEntityService,
UserRepository $userRepository,
ApiUsageRepository $apiUsageRepository,
TranslatorInterface $translator,
UserService $userService
)
{
$this->entityManager = $entityManager;
$this->abstractEntityService = $abstractEntityService;
$this->userRepository = $userRepository;
$this->apiUsageRepository = $apiUsageRepository;
$this->translator = $translator;
$this->userService = $userService;
}
/**
* @throws JWTDecodeFailureException
*/
public function __invoke(ResponseEvent $event)
{
$request = $event->getRequest();
$requestUri = $request->getRequestUri();
$statusCode = $event->getResponse()->getStatusCode();
if (strpos($requestUri, 'api') == 1) {
$log = new ApiLog();
try {
if ($statusCode != 301) {
$log->setMethod($request->getMethod());
$log->setIpAddress($request->getClientIp());
$log->setHost($request->getHost());
$log->setUri($requestUri);
$log->setCode($statusCode);
$user = $this->abstractEntityService->getUser($request);
if ($user) {
$log->setUser($user);
// notes User access check
$hasAccess = $this->userService->userHasAccess($user);
if (!$hasAccess) {
throw new \Exception($this->translator->trans('user.access.denied'), Response::HTTP_FORBIDDEN);
}
}
$log->setTimestamp(new DateTime());
$log->setUserAgent($request->headers->get('user-agent'));
$apiKey = $request->headers->get('api-key');
if ($apiKey) {
$log->setApiKey($apiKey);
$log->setPublicUsage(true);
$user = $this->userRepository->findOneByApiKey($apiKey);
$userApiUsage = 0;
if ($user) {
$log->setUser($user);
$userApiUsage = $user->getApiUsage();
}
// notes Api usage check
$apiUsage = $this->apiUsageRepository->findOneByApiKey($apiKey);
if ($apiUsage) {
$counter = $apiUsage->getCounter();
$limit = $apiUsage->getLimit();
if($limit){
if ($limit <= $counter) {
throw new \Exception($this->translator->trans('api.usage.limit.exceeded'), Response::HTTP_FORBIDDEN);
}
}
if (!$apiUsage->isActive()) {
throw new \Exception($this->translator->trans('api.usage.account.suspended'), Response::HTTP_FORBIDDEN);
}
$apiUsage->setCounter($counter + 1);
$this->entityManager->persist($apiUsage);
$this->entityManager->flush();
}
}
$requestData = $request->request->all();
$log->setRequestData($requestData);
$requestHeaders = $request->headers->all();
$log->setRequestHeaders($requestHeaders);
$responseData = $event->getResponse()->getContent();
$log->setResponseData($responseData);
$responseHeaders = $event->getResponse()->headers->all();
$log->setResponseHeaders($responseHeaders);
}
} catch (\Exception $exception) {
$log->setCode($exception->getCode());
$event->setResponse(new JsonResponse([
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
], $exception->getCode()));
}
$this->entityManager->persist($log);
$this->entityManager->flush();
}
}
}