<?php
/**
* Created by PhpStorm.
* User: uwethiess
* Date: 26.09.16
* Time: 14:45
*/
namespace App\Controller;
use App\Api\ProthelisApi;
use App\Entity\Order;
use App\Entity\Payment;
use App\Entity\User;
use App\Form\DataExportForm;
use App\Form\StorageTimeForm;
use App\Form\UserDeleteAccountForm;
use App\Form\UserUnlinkDeviceForm;
use App\Form\UserEditForm;
use App\Form\UserSignupForm;
use App\Repository\OrderRepository;
use App\Security\LoginFormAuthenticator;
use App\Service\DBLogService;
use App\Service\SubscriptionService;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat as PhoneNumberFormatAlias;
use libphonenumber\PhoneNumberUtil;
use Misd\PhoneNumberBundle\Templating\Helper\PhoneNumberHelper;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Guard\GuardAuthenticatorHandler;
use Symfony\Contracts\Translation\TranslatorInterface;
class AccountController extends AbstractController
{
/** @var DBLogService $dbLogService */
private $dbLogService;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var GuardAuthenticatorHandler
*/
private $authenticatorHandler;
/**
* @var LoginFormAuthenticator
*/
private $authenticator;
/**
* @var TranslatorInterface
*/
private $translator;
/**
* @var UserPasswordEncoderInterface
*/
private $encoder;
private RequestStack $requestStack;
private SubscriptionService $subscriptionService;
/**
* AccountController constructor.
*/
public function __construct(DBLogService $dbLogService, EntityManagerInterface $entityManager, GuardAuthenticatorHandler $authenticatorHandler, LoginFormAuthenticator $authenticator, TranslatorInterface $translator, UserPasswordEncoderInterface $encoder, RequestStack $requestStack, SubscriptionService $subscriptionService)
{
$this->dbLogService = $dbLogService;
$this->entityManager = $entityManager;
$this->authenticatorHandler = $authenticatorHandler;
$this->authenticator = $authenticator;
$this->translator = $translator;
$this->encoder = $encoder;
$this->requestStack = $requestStack;
$this->subscriptionService = $subscriptionService;
}
/**
* @Route("/prothelis-info", name="consent-notification")
* @param Request $request
* @return Response
*/
public function consentAction(Request $request)
{
return $this->render('account/consent-notification.html.twig');
}
/**
* @Route("/signup", name="user_signup")
* @param Request $request
* @return Response
*/
public function signupAction(Request $request)
{
$form = $this->createForm(UserSignupForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var User $user */
$user = $form->getData();
$user->setIsTempUser(false);
$user->setLocale('de');
$user->setSignupDate(new DateTime());
$user->setConsentTransfer(0);
if ($user->getAddressCountry() === 'DE') {
// vorübergehend Abo-Option nicht anbieten wegen Umstellungen zur Prothelis Tech GmbH
// $user->setTags([User::TAG_ENABLE_ABO]);
$user->setTags(['']);
} else {
$user->setTags(['']);
}
$registerResult = $this->registerUserApi($user);
if ($registerResult === true) {
$this->entityManager->persist($user);
$this->entityManager->flush();
$this->addFlash('success', 'Welcome ' . $user->getFirstName() . ' ' . $user->getLastName());
$this->dbLogService->info('signup', 'success', [$registerResult, $user->getId(), $user->getUsername()]);
return $this->authenticatorHandler->authenticateUserAndHandleSuccess($user, $request, $this->authenticator, 'main');
} else {
// api error
$this->addFlash('error', '' . $registerResult);
$this->dbLogService->info('signup', 'failed', [$registerResult, $user->getUsername()]);
}
} else {
// dump($form->getErrors());
}
return $this->render('activation/userform.html.twig', ['userdataForm' => $form->createView(),]);
}
private function registerUserApi(User $user)
{
$phoneNumberUtil = PhoneNumberUtil::getInstance();
$phone1 = $phoneNumberUtil->format($user->getPhoneNumber(), PhoneNumberFormatAlias::INTERNATIONAL);
$phone2 = '';
if ($user->getPhoneNumber2() instanceof PhoneNumber) {
$phone2 = $phoneNumberUtil->format($user->getPhoneNumber2(), PhoneNumberFormatAlias::INTERNATIONAL);
}
$userdata = [
'method' => 'activation',
'username' => $user->getUsername(),
'email' => $user->getEmailAddress(),
'password' => $user->getPlainPassword(),
'password2' => $user->getPlainPassword(),
'salut' => $user->getSalutation(),
'firstname' => $user->getFirstName(),
'lastname' => $user->getLastName(),
'address' => $user->getAddressStreetNo(),
'address2' => $user->getAddressStreetAdd() . '',
'postal' => $user->getAddressPostalCode(),
'city' => $user->getAddressCity(),
'country' => $user->getAddressCountry(),
'phone1' => $phone1, 'phone2' => $phone2,
];
$response = ProthelisApi::postUser($userdata);
if (@$response->error) {
//error
return $this->translator->trans('profile.' . $response->error) . ' ' . $this->translator->trans('api.err.' . $response->reason);
} else {
//success
$apiUser = ProthelisApi::getUserFromApi($user->getUsername(), $user->getPlainPassword());
$this->dbLogService->debug('api', 'signup', ['user' => $user, 'apiUser' => $apiUser], null, null);
$user->setIdApi($apiUser->getIdApi());
return true;
}
}
/**
* @Route("/dashboard", name="user_account")
*/
public function dashboardAction(Request $request)
{
$user = $this->getUser();
$orders = $this->entityManager->getRepository(Order::class)->findAllDefaultNotCalceledFromUser($user);
$hasDevicesWithSms = count($this->entityManager->getRepository(Order::class)->findTrackersWithSms($user)) > 0;
// $apiUser = ProthelisApi::getUserById($user->getIdApi());
// $sms_total = $apiUser->sms_total ?? 0;
// $sms_used = $apiUser->sms_used ?? 0;
// $sms_remaining = $apiUser->sms_remaining ?? 0;
// dump([$sms_total, $sms_used, $sms_remaining]);
$devices = [];
foreach ($orders as $o) {
if (!isset($devices[$o->getDeviceCode()])) {
$devices[$o->getDeviceCode()] = [
'detail' => [],
'orders' => [],
];
}
$devices[$o->getDeviceCode()]['orders'][] = $o;
}
foreach ($devices as $dk => $dv) {
$devices[$dk]['detail'] = $this->getDeviceSummary($dv['orders']);
}
$this->requestStack->getSession()->set('orderList', $devices);
$devicesList = [
'active' => [],
'inactive' => [],
'total' => 0,
];
foreach ($devices as $device) {
if ($device['detail']['status'] === 'active' || $device['detail']['status'] === 'activating' || $device['detail']['status'] === 'processing') {
$devicesList['active'][] = $device;
} else {
$devicesList['inactive'][] = $device;
}
$devicesList['total']++;
}
return $this->render('account/dashboard.html.twig', [
'user' => $user,
'devices' => $devicesList,
'showExtraOrder' => $hasDevicesWithSms,
]);
}
/**
* @Route("/device/{sn}", requirements={"sn" = "[A-Z0-9]+"}, name="device_overview")
*/
public function deviceOverviewAction($sn, Request $request) {
$this->entityManager = $this->getDoctrine()->getManager();
$devices = $this->requestStack->getSession()->get('orderList');
$orders = [];
$payments = [];
if (!$devices) {
return $this->redirectToRoute('user_account');
}
$orders = ['detail' => $devices[$sn]['detail'], 'orders' => []]; //$devices[$sn];
/** @var Order[] $allorders */
$allorders = $this->entityManager->getRepository(Order::class)->findAllDefaultNotCalceledFromUser($this->getUser());
foreach ($allorders as $o) {
if ($o->getDeviceCode() == $sn) {
$orders['orders'][] = $o;
}
}
$payments = $this->entityManager->getRepository(Payment::class)->findPastByUserAndDevice($this->getUser(), $sn);
/**
* Export Form
*/
$displayExportForm = $this->userIsOwner($sn);
$exportForm = $this->createForm(DataExportForm::class);
if ($displayExportForm) {
$exportForm->get('deviceCode')->setData($sn);
$exportForm->handleRequest($request);
$fixtime = $exportForm->get('fixtime')->getData();
if ($fixtime === 'user_defined') {
if ($exportForm->get('dateFrom')->isEmpty()) {
$exportForm->get('dateFrom')->addError(new FormError(''));
}
if ($exportForm->get('dateTo')->isEmpty()) {
$exportForm->get('dateTo')->addError(new FormError(''));
}
}
if ($exportForm->isSubmitted() && $exportForm->isValid()) {
switch ($fixtime) {
case 'all':
$date_from = 'all';
$date_to = 'all';
break;
case 'current_month':
$date_from = date('Y-m-01 00:00:00');
$date_to = date('Y-m-01 00:00:00', strtotime('now + 1 month'));
break;
case 'last_month':
$date_from = date('Y-m-01 00:00:00', strtotime('now - 1 month'));
$date_to = date('Y-m-01 00:00:00');
break;
case 'user_defined':
if (!empty($exportForm->get('dateFromUTC')->getData())) {
$date_from = $exportForm->get('dateFromUTC')->getData()->format('Y-m-d H:i:s');
$date_to = $exportForm->get('dateToUTC')->getData()->format('Y-m-d H:i:s');
} else {
$date_from = $exportForm->get('dateFrom')->getData()->format('Y-m-d H:i:s');
$date_to = $exportForm->get('dateTo')->getData()->format('Y-m-d H:i:s');
}
break;
}
// $this->requestStack->getSession()->getBag('exportForm_success')->clear();
if ($exportForm->getClickedButton()->getName() === 'export_kml') {
ProthelisApi::sendHistoryExportEmail($orders['detail']['deviceCode'], $date_from, $date_to, $this->getUser()->getIdApi(), 'kml');
$this->addFlash('exportForm_success', 'account.export.msg_success_kml');
} elseif ($exportForm->getClickedButton()->getName() === 'export_csv') {
ProthelisApi::sendHistoryExportEmail($orders['detail']['deviceCode'], $date_from, $date_to, $this->getUser()->getIdApi(), 'csv');
$this->addFlash('exportForm_success', 'account.export.msg_success_csv');
} elseif ($exportForm->getClickedButton()->getName() === 'export_gpx') {
ProthelisApi::sendHistoryExportEmail($orders['detail']['deviceCode'], $date_from, $date_to, $this->getUser()->getIdApi(), 'gpx');
$this->addFlash('exportForm_success', 'account.export.msg_success_gpx');
}
} elseif ($exportForm->isSubmitted()) {
$this->addFlash('exportForm_error', 'account.export.msg_error_check_input');
}
}
/**
* Storage Time Form
*/
// $device_details = ProthelisApi::getDeviceDetails($this->getUser()->getIdApi(), $orders['detail']['deviceCode'], false);
// $storageTime = $device_details->storage_days ?: 0;
$storageForm = $this->createForm(StorageTimeForm::class);
// $storageForm->get('deviceCode')->setData($orders['detail']['deviceCode']);
// $storageForm->get('storageTime')->setData($storageTime);
//
// $storageForm->handleRequest($request);
// if ($storageForm->isValid()) {
// $res = ProthelisApi::setDeviceProperty($sn, 'storage_days', intval($storageForm->get('storageTime')->getData()));
// if ($res == 'ok') {
// $this->addFlash('storageForm_success', 'account.storage.msg_success');
// } elseif ($storageForm->isSubmitted()) {
// $this->addFlash('storageForm_error', 'account.storage.msg_failed');
// }
// }
/**
* Delete Data form
*/
$displayDeleteForm = $displayExportForm;
$deviceDeleteConfirmForm = $this->createForm(UserUnlinkDeviceForm::class);
if ($displayDeleteForm) {
$deviceDeleteConfirmForm->handleRequest($request);
if ($deviceDeleteConfirmForm->isSubmitted() && $deviceDeleteConfirmForm->isValid()) {
$providedPassword = $deviceDeleteConfirmForm->get('_password')->getData();
$passwordOk = $providedPassword && $this->encoder->isPasswordValid($this->getUser(), $providedPassword);
if (!$passwordOk) {
$this->addFlash('deviceDeleteConfirmForm_error', 'account.export.msg_error_check_password');
} else {
switch ($deviceDeleteConfirmForm->get('_choice')->getData()) {
case 'history':
$unlinked = ProthelisApi::deleteDeviceHistoryData($orders['detail']['deviceCode'], $this->getUser()->getIdApi());
if ($unlinked) {
$this->addFlash('success', 'account.delete_history.msg_success');
} else {
$this->addFlash('error', 'account.delete_history.msg_error');
}
return $this->redirectToRoute('user_account');
break;
case 'unlink':
$unlinked = ProthelisApi::unlinkDeviceAndDeleteData($orders['detail']['deviceCode'], $this->getUser()->getIdApi());
if ($unlinked) {
//cancel orders
/** @var OrderRepository $orderRepository */
$orderRepository = $this->entityManager->getRepository(Order::class);
$orderRepository->cancelRemainingRuntimeOrders($orders['detail']['deviceCode'], $this->getUser());
$this->addFlash('success', 'account.unlink_device.msg_success');
} else {
$this->addFlash('error', 'account.unlink_device.msg_error');
}
return $this->redirectToRoute('user_account');
break;
default:
}
}
}
}
return $this->render('account/overview_device.html.twig', [
'orders' => $orders,
'exportForm' => $exportForm->createView(),
'storageForm' => $storageForm->createView(),
'deviceDeleteConfirmForm' => $deviceDeleteConfirmForm->createView(),
'displayExportForm' => $displayExportForm,
'displayDeleteForm' => $displayDeleteForm,
'hasActiveSubscription' => $this->subscriptionService->hasActiveSubscription($sn),
'cancelDate' => $this->subscriptionService->getCancelDate($sn),
'payments' => $payments,
]);
}
/**
* @Route("/packets/", name="extra_overview")
*/
public function extraOverviewAction(Request $request)
{
$this->entityManager = $this->getDoctrine()->getManager();
/** @var Order[] $orders */
$orders = $this->entityManager->getRepository(Order::class)->findAllExtraFromUser($this->getUser());
$apiUser = ProthelisApi::getUserById($this->getUser()->getIdApi());
$sms_total = $apiUser->sms_total ?? 0;
$sms_used = $apiUser->sms_used ?? 0;
$sms_remaining = $apiUser->sms_remaining ?? 0;
return $this->render('account/overview_extra.html.twig', [
'orders' => $orders,
'sms' => [
'total' => $sms_total,
'remaining' => $sms_remaining,
],
]);
}
protected function getDeviceSummary($orders) {
/** @var Order[] $orders */
$ret = [
'deviceCode' => $orders[0]->getDeviceCode(),
'dateStart' => $orders[0]->getDateStart(),
'dateEnd' => $orders[0]->getDateEnd(),
'status' => 'active',
'deviceType' => $orders[0]->getDeviceType(),
];
$isActiveNow = false;
$now = new DateTime("now");
foreach ($orders as $o) {
if ($o->getDateStart() <= $now && $o->getDateEnd() >= $now && in_array($o->getCurrentStatus(), ['active', 'activating'], true)) {
$isActiveNow = true;
}
if (in_array($o->getCurrentStatus(), ['active', 'activating'], true)) {
$ret['dateStart'] = min($o->getDateStart(), $ret['dateStart']);
$ret['dateEnd'] = max($o->getDateEnd(), $ret['dateEnd']);
}
// if ($o->getCurrentStatus() !== 'active') {
$ret['status'] = $o->getCurrentStatus();
/** @var User $user */
$user = $this->getUser();
if ($user->getCustomer()) {
$ret['status'] = $o->getRentalStatus();
}
// }
}
if ($isActiveNow) {
$ret['status'] = 'active';
}
return $ret;
}
/**
* @Route("/edit", name="user_edit")
* @return Response
*/
public function editAction(Request $request)
{
$userdata = $this->entityManager->getRepository(User::class)->find($this->getUser()->getId());
$form = $this->createForm(UserEditForm::class, $userdata);
$accountDeleteConfirmForm = $this->createForm(UserDeleteAccountForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var User $data */
$data = $form->getData();
// $this->entityManager->persist($data);
ProthelisApi::updateApiUser($data);
if ($data->getAddressCountry() === 'DE') {
$data->addTag(User::TAG_ENABLE_ABO);
} else {
$data->removeTag(User::TAG_ENABLE_ABO);
}
$this->entityManager->flush();
return $this->redirectToRoute('user_account');
}
$accountDeleteConfirmForm->handleRequest($request);
if ($accountDeleteConfirmForm->isSubmitted() && $accountDeleteConfirmForm->isValid()) {
$providedPassword = $accountDeleteConfirmForm->get('_password')->getData();
$passwordOk = $providedPassword && $this->encoder->isPasswordValid($this->getUser(), $providedPassword);
if (!$passwordOk) {
$this->addFlash('accountDeleteConfirmForm_error', 'account.export.msg_error_check_password');
} else {
/** @var User $user */
$user = $this->getUser();
$user->setDeleteAfter(new DateTime('now +24 hours'));
$this->entityManager->flush();
$this->addFlash('success', 'account.delete_account.msg_init');
}
}
return $this->render('account/userform.html.twig', ['user' => $this->getUser(), 'userdataForm' => $form->createView(), 'accountDeleteConfirmForm' => $accountDeleteConfirmForm->createView()]);
}
/**
* @Route("/edit/abort", name="abort_deletion")
* @return Response
*/
public function abortDeletionAction(Request $request)
{
/** @var User $user */
$user = $this->getUser();
$user->setDeleteAfter(null);
$this->entityManager->flush();
$this->addFlash('success', 'account.delete_account.msg_abort');
return $this->redirectToRoute('user_edit');
}
/**
* @Route("/cancelSubscription/{sn}", requirements={"sn" = "[A-Z0-9]+"}, name="cancel_subscription")
*/
public function cancelSubscriptionAction($sn, Request $request)
{
$cancelDate = $this->subscriptionService->getCancelDate($sn);
if (!$cancelDate) {
// no subscription
return $this->redirectToRoute('user_account');
}
$form = $this->createFormBuilder()
->add('yes', SubmitType::class, ['label' => 'account.subscription.cancel_now'])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
if ($this->subscriptionService->cancelSubscription($sn)) {
$this->addFlash('success', $this->translator->trans('account.subscription.cancel_success', ['%deviceCode%' => $sn, '%cancelDate%' => $cancelDate->format('d.m.Y')]));
$this->dbLogService->info('order', 'cancelSubscription', ['status' => 'success', 'deviceCode' => $sn, 'userId' => $this->getUser()->getId()]);
} else {
$this->addFlash('error', $this->translator->trans('account.subscription.cancel_failed', ['%deviceCode%' => $sn]));
$this->dbLogService->info('order', 'cancelSubscription', ['status' => 'failed', 'deviceCode' => $sn, 'userId' => $this->getUser()->getId()]);
}
return $this->redirectToRoute('device_overview', ['sn' => $sn]);
}
return $this->render('account/cancel_subscription.html.twig',
[
'cancelForm' => $form->createView(),
'deviceCode' => $sn,
'cancelDate' => $cancelDate,
]);
}
protected function userIsOwner($device_sn) {
try {
$idApi = $this->getUser()->getIdApi();
$device = ProthelisApi::getDevice($device_sn);
if (!$device) {
return false;
}
foreach ($device->owners as $owner) {
if ($owner->user_id === $idApi) {
return true;
}
}
} catch (\Exception $exception) {
return false;
}
return false;
}
}