<?php
namespace App\Controller\Frontend\Customer;
use App\Entity\Assay\Assay;
use App\Entity\Customer\Customer;
use App\Entity\Customer\CustomerArea;
use App\Entity\Customer\DeleteAccounts;
use App\Entity\QrCode\QrAssayRelation;
use App\Entity\QrCode\QRData;
use App\Entity\User\User;
use App\Form\Type\Frontend\Base64UploadedFileType;
use App\Form\Type\Frontend\CustomerAreaType;
use App\Form\Type\Frontend\CustomerType;
use App\Form\Type\Frontend\DeleteAccountType;
use App\Service\AccessTokenService;
use App\Uploader\CustomerAreaUploader;
use App\Uploader\CustomerUploader;
use App\ViewModel\Frontend\AccessTokenViewModel;
use App\Service\StabVidaTokenService;
use App\ViewModel\Frontend\StabVidaTokenViewModel;
use App\ViewModel\Frontend\CustomerAreaViewModel;
use App\ViewModel\Frontend\CustomerViewModel;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Nelmio\ApiDocBundle\Annotation\Model;
use Nelmio\ApiDocBundle\Annotation\Security;
use OpenApi\Annotations as OA;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class CustomersController
*
* @package App\Controller
*/
class CustomersController extends AbstractController {
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var FormFactoryInterface
*/
private $formFactory;
/**
* @var CustomerUploader
*/
private $customerUploader;
/**
* @var CustomerAreaUploader
*/
private $customerAreaUploader;
/**
* @var UserPasswordEncoderInterface
*/
private $passwordEncoder;
/**
* @var AccessTokenService
*/
private $accessTokenService;
/**
* @var StabVidaTokenService
*/
private $stabVidaTokenService;
/**
* CustomersController constructor.
*
* @param EntityManagerInterface $entityManager
* @param FormFactoryInterface $formFactory
* @param AccessTokenService $accessTokenService
* @param StabVidaTokenService $stabVidaTokenService
* @param UserPasswordEncoderInterface $passwordEncoder
* @param CustomerUploader $customerUploader ,
* @param CustomerAreaUploader $customerAreaUploader
*/
public function __construct(
EntityManagerInterface $entityManager,
FormFactoryInterface $formFactory,
AccessTokenService $accessTokenService,
StabVidaTokenService $stabVidaTokenService,
UserPasswordEncoderInterface $passwordEncoder,
CustomerUploader $customerUploader,
CustomerAreaUploader $customerAreaUploader
) {
$this->entityManager = $entityManager;
$this->formFactory = $formFactory;
$this->accessTokenService = $accessTokenService;
$this->stabVidaTokenService = $stabVidaTokenService;
$this->passwordEncoder = $passwordEncoder;
$this->customerUploader = $customerUploader;
$this->customerAreaUploader = $customerAreaUploader;
}
/**
* Get the currently logged-in customer profile
*
* @Route(path="/me", methods={"GET"})
* @Security(name="Bearer")
* @OA\Response(
* response="200",
* ref="#/components/schemas/Customer"
* )
* @OA\Response(
* response="401",
* description="Authentication needed",
* ref="#/components/schemas/UnauthorizedResponseError"
* )
*/
public function meAction(): JsonResponse {
$customer = $this->entityManager
->getRepository(Customer::class)
->getCustomerForUser($this->getUser());
return $this->json($customer, 200, [], CustomerViewModel::create($customer, $this->customerUploader));
}
/**
* Update customer information
*
* @Route(path="/me", methods={"PATCH"})
* @param Request $request
* @return JsonResponse
* @throws Exception
* @Security(name="Bearer")
* @OA\Response(
* response="200",
* description="The access token",
* @Model(type=AccessTokenViewModel::class)
* )
* @OA\Response(
* response="400",
* description="Authentication needed",
* ref="#/components/schemas/BadRequestError"
* )
* @OA\Response(
* response="401",
* description="Authentication needed",
* ref="#/components/schemas/UnauthorizedResponseError"
* )
* @OA\Response(
* response="404",
* description="Invalid password",
* ref="#/components/schemas/NotFoundError"
* )
* @OA\Response(
* response="409",
* description="Invalid e-mail",
* ref="#/components/schemas/ConflictError"
* )
*/
public function updateAction(Request $request): JsonResponse {
/** @var User $user */
$user = $this->getUser();
$customer = $this->entityManager
->getRepository(Customer::class)
->getCustomerForUser($user);
$form = $this->formFactory->create(CustomerType::class, $customer);
$form->submit(json_decode($request->getContent(), true));
if(!$form->isSubmitted() || !$form->isValid()) {
throw new BadRequestHttpException($form->getErrors(true, false)); // 400 - Bad Request
}
$currentPassword = $form->get('currentPassword')->getData();
$plainPassword = $form->get('password')->getData();
if(!$this->passwordEncoder->isPasswordValid($user, $currentPassword)) {
throw new NotFoundHttpException();
}
$this->entityManager->beginTransaction();
if($customer->getEmail() !== $user->getEmail()) {
$existingUser = $this->entityManager
->getRepository(User::class)
->findOneBy(['email' => $customer->getEmail()]);
if($existingUser !== null) {
throw new ConflictHttpException(); //409 - Conflict
}
$user->setEmail($customer->getEmail());
}
if(!empty($plainPassword)) {
$passwordEncoded = $this->passwordEncoder->encodePassword($user, $plainPassword);
$user->setPassword($passwordEncoded);
$user->setResetPasswordToken(null);
$user->setResetPasswordExpiresAt(null);
}
$this->entityManager->persist($user);
$this->entityManager->persist($customer);
$this->entityManager->flush();
$this->entityManager->commit();
$accessToken = $this->accessTokenService->createAccessToken($user);
return $this->json(AccessTokenViewModel::create($accessToken));
}
/**
* Get customer settings
*
* @Route(path="/myArea", methods={"GET"})
* @Security(name="Bearer")
* @OA\Response(
* response="200",
* ref="#/components/schemas/CustomerArea"
* )
* @OA\Response(
* response="401",
* description="Authentication needed",
* ref="#/components/schemas/UnauthorizedResponseError"
* )
*/
public function myAreaAction(): JsonResponse {
$customerArea = $this->entityManager
->getRepository(CustomerArea::class)
->getCustomerAreaForUser($this->getUser());
if(!$customerArea) {
$customerArea = new CustomerArea();
$customerArea->setUser($this->getUser());
$this->entityManager->persist($customerArea);
$this->entityManager->flush();
}
return $this->json(
$customerArea,
200,
[],
CustomerAreaViewModel::create($customerArea, $this->customerAreaUploader)
);
}
/**
* Update customer settings
*
* @Route(path="/setMyArea", methods={"POST"})
* @Security(name="Bearer")
* @OA\RequestBody(
* @Model(type=CustomerAreaType::class)
* )
* @OA\Response(
* response="200",
* ref="#/components/schemas/CustomerArea"
* )
* @OA\Response(
* response="400",
* ref="#/components/schemas/BadRequestError"
* )
* @OA\Response(
* response="401",
* description="Authentication needed",
* ref="#/components/schemas/UnauthorizedResponseError"
* )
*/
public function setMyArea(Request $request): JsonResponse {
$customerArea = $this->entityManager
->getRepository(CustomerArea::class)
->getCustomerAreaForUser($this->getUser());
$customerAreaForm = $this->formFactory
->create(CustomerAreaType::class, $customerArea);
$customerAreaForm->submit(json_decode($request->getContent(), true));
if(!$customerAreaForm->isSubmitted() || !$customerAreaForm->isValid()) {
throw new BadRequestHttpException($customerAreaForm->getErrors());
}
/** @var UploadedFile $uploadedFile */
$uploadedFile = $customerAreaForm->get('signature')->getData();
/** @var CustomerArea $newArea * */
$newArea = $customerAreaForm->getData();
if (isset($uploadedFile)) {
$uploadedFilename = $this->customerAreaUploader->upload($uploadedFile);
$newArea->setSignatureFilename($uploadedFilename);
}
else {
$newArea->setSignatureFilename(null);
}
$this->entityManager->persist($newArea);
$this->entityManager->flush();
return $this->json($newArea, 200, [], CustomerAreaViewModel::VIEW_CONTEXT);
}
/**
* Upload customer logo
*
* @Route(path="/uploadLogo", methods={"POST"})
* @param Request $request
* @return JsonResponse
* @Security(name="Bearer")
* @OA\RequestBody(
* @Model(type=Base64UploadedFileType::class)
* )
* @OA\Response(
* response="200",
* description="Empty response",
* @OA\Schema(type="array")
* )
* @OA\Response(
* response="400",
* ref="#/components/schemas/BadRequestError"
* )
* @OA\Response(
* response="401",
* description="Authentication needed",
* ref="#/components/schemas/UnauthorizedResponseError"
* )
*/
public function uploadLogo(Request $request): JsonResponse {
/** @var Customer $customer */
$customer = $this->entityManager
->getRepository(Customer::class)
->getCustomerForUser($this->getUser());
$form = $this->formFactory
->create(
Base64UploadedFileType::class,
null,
[
'constraints' => [
new Assert\Image(),
],
]
);
$form->submit($request->getContent());
if(!$form->isSubmitted() || !$form->isValid()) {
throw new BadRequestHttpException($form->getErrors());
}
/** @var UploadedFile $uploadedFile */
$uploadedFile = $form->getData();
if(isset($uploadedFile)) {
$uploadedFilename = $this->customerUploader->upload($uploadedFile);
$customer->setLogoFilename($uploadedFilename);
}
else {
$customer->setLogoFilename(null);
}
$this->entityManager->persist($customer);
$this->entityManager->flush();
return $this->json([]);
}
/**
* Delete the customer account
*
* @Route(path="/deleteAccount", methods={"PATCH"})
* @param Request $request
* @return JsonResponse
* @throws Exception
* @Security(name="Bearer")
* @OA\RequestBody(
* @Model(type=DeleteAccountType::class)
* )
* @OA\Response(
* response="200",
* description="Empty response",
* @OA\Schema(type="array")
* )
* @OA\Response(
* response="400",
* ref="#/components/schemas/BadRequestError"
* )
* @OA\Response(
* response="401",
* description="Authentication needed",
* ref="#/components/schemas/UnauthorizedResponseError"
* )
* @OA\Response(
* response="404",
* description="Invalid password",
* ref="#/components/schemas/NotFoundError"
* )
* @OA\Response(
* response="409",
* description="Conflict",
* ref="#/components/schemas/ConflictError"
* )
*/
public function deleteAccountAction(Request $request): JsonResponse {
$user = $this->getUser();
$customer = $this->entityManager
->getRepository(Customer::class)
->getCustomerForUser($user);
$form = $this->formFactory->create(DeleteAccountType::class, null);
$form->submit(json_decode($request->getContent(), true));
if(!$form->isSubmitted() || !$form->isValid()) {
throw new BadRequestHttpException($form->getErrors(true, false)); // 400 - Bad Request
}
$email = $form->get('email')->getData();
$currentPassword = $form->get('currentPassword')->getData();
if(!$this->passwordEncoder->isPasswordValid($user, $currentPassword)) {
throw new NotFoundHttpException();
}
$this->entityManager->beginTransaction();
if($customer->getEmail() === $user->getEmail()) {
$existingUser = $this->entityManager
->getRepository(User::class)
->findOneBy(['email' => $user->getUsername()]);
if($existingUser === null) {
throw new ConflictHttpException(); //409 - Conflict
}
if($email !== $user->getEmail()) {
throw new ConflictHttpException(); //409 - Conflict
}
$pocketsInfo = $this->entityManager
->getRepository(Assay::class)
->getDistinctHardwareVersionDevicesFromAssays($user);
$pocketsSts = "";
$i = 0;
foreach($pocketsInfo as $jsonPockets) {
$pockets = $jsonPockets['hardwareVersion'];
if(trim($pockets) != null) {
if($i > 0) {
$pocketsSts = $pocketsSts.";".$pockets;
}
else {
$pocketsSts = $pockets;
}
$i++;
}
}
$IdsInfo = $this->entityManager
->getRepository(Assay::class)
->getAssaysIds($user);
$idsSt = "";
$i = 0;
foreach ($IdsInfo as $jsonIds) {
$ids = $jsonIds['assayId'];
if(trim($ids) != null) {
if($i > 0) {
$idsSt = $idsSt.";".$ids;
}
else {
$idsSt = $ids;
}
$i++;
}
}
$deleteAcc = new DeleteAccounts();
$deleteAcc->setUserId($customer->getCustomerId());
$deleteAcc->setAssayIds($idsSt);
$deleteAcc->setPockets($pocketsSts);
$deleteAcc->setDeleteDatetime(new DateTime());
$this->entityManager->persist($deleteAcc);
//######### DELETE QR DATA ############//
$qrData = $this->entityManager
->getRepository(QRData::class)
->deleteQrDataByUser($user);
$qrAssayRelation = $this->entityManager
->getRepository(QrAssayRelation::class)
->deleteQrAssayRelationByUser($user);
//######### DELETE USER AND CASCADE ############//
$this->entityManager->remove($user);
// ON DELETE CASCADE // //# UESRS #//
//# ACCESS TOKEN #// //# ASSAYS #// //# ASSAY_DATA #//
//# ASSAY_RESULTS #// //# CUSTOMERS #// //# CUSTOMER_AREA #//
$this->entityManager->flush();
$this->entityManager->commit();
}
else {
throw new ConflictHttpException(); //409 - Conflict
}
return $this->json([]);
}
/**
* Get the stab vida access token
*
* @Route(path="/stabVidaToken", methods={"GET"})
* @Security(name="Bearer")
* @OA\Response(
* response="200",
* description="The stab vida access token",
* @Model(type=StabVidaTokenViewModel::class)
* )
* @OA\Response(
* response="400",
* ref="#/components/schemas/BadRequestError"
* )
* @throws Exception
*/
public function getStabVidaAccessToken(): JsonResponse {
$user = $this->getUser();
$stabVidaToken = $this->stabVidaTokenService->getStabVidaToken($user);
if($stabVidaToken === null) {
throw new BadRequestHttpException("User is not registered in clients.stabvida.com");
}
$stabVidaTokenViewModel = StabVidaTokenViewModel::create($stabVidaToken);
return $this->json($stabVidaTokenViewModel);
}
}