<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Translation\TranslatorInterface;
use Psr\Log\LoggerInterface;
use App\Util\PMA;
use App\Form\CampaignForm;
use App\Form\VariableForm;
use App\Form\PMAVariableForm;
use App\Entity\VariableDefinition;
use App\Entity\CampaignMailing;
use App\Repository\VariableDefinitionRepository;
use App\Repository\OrganizationRepository;
use App\Repository\CampaignMailingRepository;
use App\Util\AC;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
class AdminController extends AbstractController
{
private $requestStack;
private $logger;
private $translator;
private $organizationRepository;
public function __construct(
RequestStack $requestStack, LoggerInterface $logger, TranslatorInterface $translator,
OrganizationRepository $organizationRepository
)
{
$this->requestStack = $requestStack;
$this->logger = $logger;
$this->translator = $translator;
$this->organizationRepository = $organizationRepository;
}
/**
* @Route("/admin", name="app_admin")
*/
public function index(): Response
{
return $this->redirectToRoute("campaigns_list");
}
/**
* @Route("/admin/campaigns/list", name="campaigns_list")
*/
public function campaignsList(Request $request): Response
{
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$campaigns = $pma->getCampaigns($request->query->getInt('page', 0), $request->query->getInt('size', 20));
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
return $this->render('admin/campaigns_list.html.twig', [
'campaigns' => $campaigns,
]);
}
/**
* @Route("/admin/campaigns/new", name="campaigns_new")
*/
public function newCampaign(Request $request, CampaignMailingRepository $campaignMailingRepository): Response
{
$form = $this->createForm(CampaignForm::class);
$form->handleRequest($request);
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$products = $pma->getProducts();
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
if($form->isSubmitted() && $form->isValid()) {
try {
$productId = $form->get('productId')->getData();
if(is_null($productId) || $productId == '') {
$productId = 0;
}
$deliveryChecked = false;
if($form->get('deliveryCheckSelected')->getData() == true) {
$deliveryChecked = true;
}
$ret = $pma->createCampaign($form->get('campaignName')->getData(), $form->get('campaignIdExt')->getData(), $productId, $form->get('sendingReasonId')->getData(), $deliveryChecked);
$campaignId = $ret['id'];
$ret = $pma->createMailing($campaignId);
// save mailing ID
$cm = new CampaignMailing();
$cm->setCampaignId($campaignId);
$cm->setMailingId($ret['id']);
$campaignMailingRepository->add($cm, true);
$this->addFlash('success', $this->translator->trans('success message - new campaign added'));
$this->logger->info('New campaign added', ['name' => $form->get('campaignName')->getData(), 'customerId' => $customerId, 'user' => $this->getUser()->getUserIdentifier()]);
return $this->redirectToRoute("variables_list", ['mailingId' => $ret['id']]);
}
catch(\Exception $ex) {
$this->addFlash('error', $this->translator->trans('error message - saving campaign error'));
goto newCampaignRender;
}
}
elseif($form->isSubmitted() && !$form->isValid()) {
$this->addFlash('error', $this->translator->trans('error message - new campaign not added'));
}
newCampaignRender:
return $this->render('admin/campaigns_new.html.twig', [
'form' => $form->createView(),
'products' => $products,
'productTypeId' => 0,
'mailingId' => 0,
'isEdit' => false,
]);
}
/**
* @Route("/admin/campaigns/edit/{campaignId}", name="campaigns_edit")
*/
public function editCampaign(int $campaignId, Request $request, CampaignMailingRepository $campaignMailingRepository): Response
{
$form = $this->createForm(CampaignForm::class);
$form->handleRequest($request);
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$campaign = $pma->getCampaign($campaignId);
$products = $pma->getProducts();
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
$productTypeId = 0;
$cm = $campaignMailingRepository->findOneByCampaignId($campaignId);
$mailingId = 0;
if(!is_null($cm)) {
$mailingId = $cm->getMailingId();
}
if(array_key_exists('product', $campaign) && !is_null($campaign['product'])) {
$productTypeId = $campaign['product']['productTypeId'];
}
if(!$form->isSubmitted()) {
$form->get('campaignName')->setData($campaign['campaignName']);
$form->get('campaignIdExt')->setData($campaign['campaignIdExt']);
$form->get('sendingReasonId')->setData($campaign['sendingReasonId']);
$form->get('deliveryCheckSelected')->setData($campaign['deliveryCheckSelected']);
$form->get('productId')->setData($campaign['productId']);
}
else {
if($form->isSubmitted() && $form->isValid()) {
try {
$productId = $form->get('productId')->getData();
$data = [];
if(!is_null($productId) && $productId != '') {
if($productId != $campaign['productId']) {
$data['productId'] = $productId;
}
}
if($form->get('campaignName')->getData() != $campaign['campaignName']) {
$data['campaignName'] = $form->get('campaignName')->getData();
}
if($form->get('sendingReasonId')->getData() != $campaign['sendingReasonId']) {
$data['sendingReasonId'] = $form->get('sendingReasonId')->getData();
}
if($form->get('deliveryCheckSelected')->getData() != $campaign['deliveryCheckSelected']) {
$data['deliveryCheckSelected'] = $form->get('deliveryCheckSelected')->getData();
}
$pma->updateCampaign($campaignId, $data);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
goto editCampaignRender;
}
$this->addFlash('success', $this->translator->trans('success message - editing campaign OK'));
$this->logger->info('Campaign edited', ['name' => $form->get('campaignName')->getData(), 'customerId' => $customerId, 'user' => $this->getUser()->getUserIdentifier()]);
}
elseif($form->isSubmitted() && !$form->isValid()) {
$this->addFlash('error', $this->translator->trans('error message - editing campaign not ok'));
}
}
editCampaignRender:
return $this->render('admin/campaigns_new.html.twig', [
'form' => $form->createView(),
'products' => $products,
'productTypeId' => $productTypeId,
'mailingId' => $mailingId,
'isEdit' => true,
]);
}
/**
* @Route("/admin/campaigns/del/{campaignId}", name="campaigns_del")
*/
public function delCampaign(int $campaignId, Request $request, CampaignMailingRepository $campaignMailingRepository): Response
{
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$pma->delCampaign($campaignId);
}
catch(\Exception $ex) {
$this->addFlash('error', $this->translator->trans('error message - error deleting campaign') . ': ' . $ex->getMessage());
}
$this->addFlash('success', $this->translator->trans('success message - campaign deleted'));
$this->logger->info('Campaign deleted', ['campaignId' => $campaignId, 'customerId' => $customerId, 'user' => $this->getUser()->getUserIdentifier()]);
// TODO - usunięcie CampaignMailing
return $this->redirectToRoute("campaigns_list");
}
/**
* shows all internal variables and allows sending them into PMA
* @Route("/admin/variables/list/{mailingId}", name="variables_list")
*/
public function variablesList(int $mailingId, Request $request, VariableDefinitionRepository $variableRepository, CampaignMailingRepository $campaignMailingRepository): Response
{
// form for creating new local variables
$form = $this->createForm(VariableForm::class);
$form->handleRequest($request);
// form for sending variables to PMA
$pmaForm = $this->createForm(PMAVariableForm::class, null, [
'action' => $this->generateUrl('variables_send')
]);
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
$internalVariables = $variableRepository->findAllForCustomerId($customerId);
try {
$pmaVariables = $pma->getVariables($mailingId);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
if($form->isSubmitted() && $form->isValid()) {
try {
$localVar = new VariableDefinition();
$localVar->setLabel($form->get('label')->getData());
$localVar->setDataTypeId($form->get('dataTypeId')->getData());
$localVar->setCustomerId($customerId);
$variableRepository->add($localVar, true);
$internalVariables = $variableRepository->findAllForCustomerId($customerId);
}
catch(\Exception $ex) {
$this->addFlash('error', $this->translator->trans('error message - saving variable error'));
goto newVariableRender;
}
$this->addFlash('success', $this->translator->trans('success message - new variable added'));
}
elseif($form->isSubmitted() && !$form->isValid()) {
$this->addFlash('error', $this->translator->trans('error message - new variable not added'));
}
$campaignId = 0;
$cm = $campaignMailingRepository->findOneByMailingId($mailingId);
if(!is_null($cm)) {
$campaignId = $cm->getCampaignId();
}
newVariableRender:
return $this->render('admin/variables_list.html.twig', [
'form' => $form->createView(),
'pmaform' => $pmaForm->createView(),
'internalVariables' => $internalVariables,
'pmaVariables' => $pmaVariables['elements'],
'mailingId' => $mailingId,
'campaignId' => $campaignId,
]);
}
/**
* fetches all custom fields from AC and save them as local variables
* @Route("/admin/variables/fetch-from-ac/{mailingId}", name="variables_fetch")
*/
public function fetchVariablesFromAC(int $mailingId, VariableDefinitionRepository $variableRepository)
{
$jwt = $this->_authenticate();
$customerId = $this->_getCustomerId($jwt);
$user = $this->getUser();
$organization = $this->organizationRepository->find($user->getOrganizationId());
$ac = new AC($organization->getAcUrl(), $organization->getAcKey());
$list = $ac->listAllCustomFields();
foreach($list as $v) {
try {
if(is_null($variableRepository->findOneByLabelAndCustomerId($v['title'], $customerId))) {
$localVar = new VariableDefinition();
$localVar->setLabel($v['title']);
$localVar->setDataTypeId(PMA::MapAcFieldTypeToPma($v['type']));
$localVar->setCustomerId($customerId);
$variableRepository->add($localVar, true);
}
}
catch(\Exception $ex) {
$this->addFlash('error', $this->translator->trans('error message - fetching variables error'));
}
}
return $this->redirectToRoute('variables_list', ['mailingId' => $mailingId]);
}
/**
* deletes internal variable
* @Route("/admin/variables/del/{variableId}/{mailingId}", name="variables_del")
*/
public function delVariable(int $variableId, int $mailingId, Request $request, VariableDefinitionRepository $variableRepository) : Response
{
$jwt = $this->_authenticate();
$var = $variableRepository->find($variableId);
if($var->getCustomerId() == $this->_getCustomerId($jwt)) {
$variableRepository->remove($var, true);
}
else {
$this->logger->error("Trying to delete variable of another customer. Var id: " . $var->getId());
throw new \Exception("Trying to delete variable of another customer", 403);
}
return $this->redirectToRoute("variables_list", ['mailingId' => $mailingId]);
}
/**
* saves defined variables into PMA mailing
* @Route("/admin/variables/send", name="variables_send")
*/
public function sendVariableDefinitions(Request $request, VariableDefinitionRepository $variableRepository) : Response
{
$form = $this->createForm(PMAVariableForm::class);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
$variables = [];
$sortOrder = 0;
$mailingId = $form->get('mailingId')->getData();
// check if there are already defined variables in PMA
try {
$ret = $pma->getVariables($mailingId);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
$pmaVariables = $ret['elements'];
if(!is_null($form->get('variableIds')->getData())) {
foreach(explode(',', $form->get('variableIds')->getData()) as $varId) {
$localVar = $variableRepository->find($varId);
$arrItem = [];
$arrItem['label'] = $localVar->getLabel();
$arrItem['dataTypeId'] = $localVar->getDataTypeId();
$arrItem['sortOrder'] = $sortOrder;
$variables[] = $arrItem;
$sortOrder = $sortOrder + 1;
}
}
if(count($pmaVariables) > 0) {
// do we need to delete some variables?
$variablesForDeletion = explode(',', $form->get('deletedPmaVariableIds')->getData());
foreach($pmaVariables as $v) {
if(in_array($v['id'], $variablesForDeletion)) {
continue;
}
$arrItem = [];
$arrItem['id'] = $v['id'];
$arrItem['label'] = $v['label'];
$arrItem['dataTypeId'] = $v['dataType']['id'];
$arrItem['sortOrder'] = $v['sortOrder'];
$variables[] = $arrItem;
}
try {
$pma->updateVariables($mailingId, $variables);
$this->logger->info('Variables updated in mailing', ['mailingId' => $mailingId, 'customerId' => $customerId, 'user' => $this->getUser()->getUserIdentifier()]);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
}
else {
try {
$pma->createVariables($mailingId, $variables);
$this->logger->info('Variables added to mailing', ['mailingId' => $mailingId, 'customerId' => $customerId, 'user' => $this->getUser()->getUserIdentifier()]);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
}
$this->addFlash('success', $this->translator->trans('success message - variables added to mailing'));
}
elseif($form->isSubmitted() && !$form->isValid()) {
$this->addFlash('error', $this->translator->trans('error message - new variable not added'));
}
return $this->redirectToRoute("variables_list", ['mailingId' => $mailingId]);
}
/**
* shows campaign summary
* @Route("/admin/campaigns/show/{campaignId}", name="campaigns_show")
*/
public function showCampaign(int $campaignId) : Response
{
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$campaign = $pma->getCampaign($campaignId);
$mailings = $pma->getMailings($campaignId);
$lookups = PMA::campaignLookups();
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
$variables = [];
foreach($mailings['elements'] as $m) {
$variables = array_merge($variables, $pma->getVariables($m['id']));
}
$campaignSendingReasonLabel = '';
foreach($lookups['SendingReason'] as $e) {
if($e['id'] == $campaign['sendingReasonId']) {
$campaignSendingReasonLabel = $e['label'];
}
}
$campaignStateLabel = '';
foreach($lookups['CampaignState'] as $e) {
if($e['id'] == $campaign['stateId']) {
$campaignStateLabel = $e['label'];
}
}
return $this->render('admin/campaigns_show_summary.html.twig', [
'campaign' => $campaign,
'mailings' => $mailings['elements'],
'variables' => $variables['elements'],
'requiredActions' => $campaign['requiredActions'],
'mailingId' => $mailings['elements'][0]['id'],
'campaignStateLabel' => $campaignStateLabel,
'campaignSendingReasonLabel' => $campaignSendingReasonLabel,
]);
}
/**
* shows error message
* @Route("/admin/error", name="show_error")
*/
public function showError() : Response
{
return $this->render('admin/show_error.html.twig');
}
/**
* shows campaign summary
* @Route("/admin/campaigns/show-report/{campaignId}", name="campaigns_show_report")
*/
public function showCampaignReport(int $campaignId) : Response
{
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$campaign = $pma->getCampaign($campaignId);
$report = $pma->getReportOverview($campaignId);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
return $this->render('admin/campaigns_show_report.html.twig', [
'campaign' => $campaign,
'report' => $report,
]);
}
/**
* shows campaign summary
* @Route("/admin/campaigns/download-report/{campaignId}/{date}", name="campaigns_download_report")
*/
public function downloadCampaignReport(int $campaignId, string $date) : Response
{
$jwt = $this->_authenticate();
$pma = new PMA($this->logger, $jwt);
$customerId = $this->_getCustomerId($jwt);
$pma->setCustomerId($customerId);
try {
$report = $pma->getReportDetailed($campaignId, $date);
}
catch(\Exception $ex) {
$this->addFlash('error', $ex->getMessage());
return $this->redirectToRoute("show_error");
}
$response = new Response();
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="PMA_report_' . $campaignId . '_' . $date . '.csv";');
$response->headers->set('Content-length', strlen($report));
// Send headers before outputting anything
$response->sendHeaders();
$response->setContent($report);
return $response;
// return $this->file($report, $date . '.csv');
}
/**
* shows campaign summary
* @Route("/admin/settings", name="app_settings")
*/
public function settings() : Response
{
$user = $this->getUser();
$organization = $this->organizationRepository->find($user->getOrganizationId());
return $this->render('admin/settings.html.twig', [
'organization' => $organization,
'user' => $user,
]);
}
/**
* logs in into PMA system
* @Route("/admin/pma/login/{campaignId}", name="pma_login")
*/
public function loginToPMA($campaignId=0) : Response
{
$user = $this->getUser();
$organization = $this->organizationRepository->find($user->getOrganizationId());
$token = PMA::createJWT(
$user->getEmail(),
$user->getFirstname(),
$user->getLastname(),
(int) $this->getParameter('app.partner_system_id_ext'),
$organization->getPartnerSystemCustomerIdExt(),
$this->getParameter('app.sso_token_key')
);
if(!array_key_exists('APP_GUI_URL', $_SERVER)) {
$this->logger->critical("no APP_GUI_URL set");
throw new \Exception("no APP_GUI_URL set", 500);
}
$url = $_SERVER['APP_GUI_URL'] . '?partnersystem=' . $token;
if($campaignId != 0) {
$url .= '&campaignid=' . $campaignId;
}
return $this->redirect($url);
}
/**
* returns already generated token or tries to get authenticated
*/
private function _authenticate() : string
{
// first get token from session
$session = $this->requestStack->getSession();
$jwt = $session->get('pmajwttoken');
// check if still valid
if(!is_null($jwt) && PMA::checkIfTokenValid($jwt)) {
return $jwt;
}
$user = $this->getUser();
$organization = $this->organizationRepository->find($user->getOrganizationId());
if(is_null($organization)) {
$this->logger->debug('CXController::_authenticate() no organization for user ' . $user->getUserIdentifier());
$this->logger->error('CXController::_authenticate() no organization for user ' . $user->getUserIdentifier());
$this->addFlash('error', $this->translator->trans('error message - no organization set'));
return $this->redirectToRoute("show_error");
}
try {
$jwt = PMA::authenticate(
(int) $this->getParameter('app.partner_system_id_ext'),
$organization->getPartnerSystemCustomerIdExt(),
$this->getParameter('app.auth_secret')
);
}
catch(\Exception $ex) {
$this->logger->debug('AdminController::_authenticate() error set: ' . $ex->getMessage() . ', errno: ' . $ex->getCode());
$this->logger->error('AdminController::_authenticate() error set');
$this->addFlash('error', $this->translator->trans('error message - authentication error'));
return $this->redirectToRoute("show_error");
}
$session->set('pmajwttoken', $jwt);
return $jwt;
}
private function _getCustomerId($jwt) : int
{
$customerIds = PMA::getCustomerIdsFromToken($jwt);
return $customerIds[0];
}
}