<?php
namespace App\Controller;
use App\Event\LoggerServiceEvent;
use App\Event\Store\StoreEvent;
use App\Service\LoggerHelper;
use App\Service\TiendaNubeApi;
use App\Service\Helper;
use App\Service\DBManager;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpClient\Exception\RedirectionException;
use Symfony\Component\HttpClient\Exception\ServerException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
/**
* Handles store management
*/
class StoresController extends AbstractController
{
private $helper, $dbm, $TNApi;
/**
* @var string
*/
private $tn_app_id;
/**
* @var string
*/
private $tn_shipping_carrier_name;
/**
* @var LoggerHelper
*/
private $loggerHelper;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
/**
* @param Helper $helper
* @param DBManager $dbm
* @param TiendaNubeApi $TNApi
* @param string $tn_app_id
* @param string $tn_shipping_carrier_name
* @param LoggerHelper $loggerHelper
* @param EventDispatcherInterface $dispatcher
*/
public function __construct(Helper $helper, DBManager $dbm, TiendaNubeApi $TNApi, string $tn_app_id, string $tn_shipping_carrier_name, LoggerHelper $loggerHelper, EventDispatcherInterface $dispatcher)
{
$this->helper = $helper;
$this->dbm = $dbm;
$this->TNApi = $TNApi;
$this->tn_app_id = $tn_app_id;
$this->tn_shipping_carrier_name = $tn_shipping_carrier_name;
$this->loggerHelper = $loggerHelper;
$this->dispatcher = $dispatcher;
}
/**
* Route for /
*
* @return Response
*/
public function index(): Response
{
$this->loggerHelper->saveMessage('Ingreso', 'Inicio', 'Registro de inicio', 200);
return $this->helper->print_json([]);
}
/**
* Authorizes the APP inside TN and create all the requirements for the APP to work
*
* @param Request $req
* @return Response
*/
public function auth(Request $req): Response
{
$res = [];
$code = $req->query->get('code', false);
if (!$code) {
$req->getUri();
$event = new StoreEvent([['error' => 'No llegó code de identificación.'], '400']);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_AUTH);
return $this->helper->render_message('Petición inválida. Por favor volvé a instalar la aplicación.');
}
try {
// 1. Auth
$res = $this->TNApi->authenticate($code);
if (empty($res['access_token']) || empty($res['user_id'])) {
$event = new StoreEvent([['error' => 'No se pudo obtener el access token. El code es inválido .'], '400']);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_AUTH);
return $this->helper->render_message(
'No se pudo obtener el access token. Por favor vuelva a instalar la aplicación.'
);
}
$this->dbm->update_access_token($res);
$store_id = $res['user_id'];
$access_token = $res['access_token'];
} catch (\Exception $e) {
$event = new StoreEvent([['error' => $e->getMessage()], $e->getCode()]);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_EVENT);
return $this->helper->render_message($e->getMessage());
} catch (TransportExceptionInterface $e) {
$event = new StoreEvent([['error' => $e->getMessage()], $e->getCode()]);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_EVENT);
return $this->helper->render_message($e->getMessage());
}
try {
// 2. Create shipping carrier
$shipping_carrier_id = $this->TNApi->create_shipping_carrier($store_id);
$this->dbm->update_shipping_carrier_id($store_id, $shipping_carrier_id);
// 3. Create Shipping carrier options
$options = array("standard"=>"Envío Normal", "priority"=>"Envío Prioritario", "express"=>"Envío Express");
foreach ($options as $code => $name) {
$res = $this->TNApi->create_shipping_carrier_options($store_id, $shipping_carrier_id, $code, $name);
}
// 4. Create webhooks
$existing_webhooks = $this->TNApi->get_existing_webhooks($store_id);
if (!$existing_webhooks['order_created'])
$res = $this->TNApi->create_order_created_webhook($store_id);
if (!$existing_webhooks['order_updated'])
$res = $this->TNApi->create_order_updated_webhook($store_id);
if (!$existing_webhooks['app_uninstalled'])
$res = $this->TNApi->create_app_uninstalled_webhook($store_id);
if (!$existing_webhooks['app_suspended'])
$res = $this->TNApi->create_app_suspended_webhook($store_id);
if (!$existing_webhooks['app_resumed'])
$res = $this->TNApi->create_app_resumed_webhook($store_id);
return $this->render_auth_form($store_id, $access_token);
} catch (ClientException | ServerException | RedirectionException $e) {
$event = new StoreEvent([['error' => $e->getResponse()->getContent(false)], 400]);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_EVENT);
return $this->helper->print_json(['error' => $e->getResponse()->getContent(false)], 400);
} catch (\Exception $e) {
$event = new LoggerServiceEvent([['error' => $e->getMessage()], 500]);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_EVENT);
return $this->helper->render_message($e->getMessage());
} catch (TransportExceptionInterface $e) {
$event = new StoreEvent([['error' => $e->getMessage()], $e->getCode()]);
$event->setUrl($req->getUri());
$this->dispatcher->dispatch($event, StoreEvent::STORE_EVENT);
return $this->helper->render_message($e->getMessage());
}
}
/**
* Handles the uninstallation of the APP
*
* @param Request $req
* @return Response
*/
public function uninstall_app(Request $req): Response
{
$webhook_content = $req->getContent();
$hmac_header = $req->headers->get('X-Linkedstore-HMAC-SHA256');
$data_received = json_decode($webhook_content, true);
if (!$this->TNApi->verify_webhook($webhook_content, $hmac_header)){
$this->procesaEvent(['error' => 'Couldn\'t verify webhook'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'Couldn\'t verify webhook'], Response::HTTP_BAD_REQUEST);
}
if (!$data_received){
$this->procesaEvent(['error' => 'Invalid JSON received'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'Invalid JSON received']);
}
if ((string)$data_received['id'] !== (string)$this->tn_app_id) {
$this->procesaEvent(['error' => 'App ID Invalid'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'App ID Invalid']);
}
$store_id = filter_var($data_received['store_id'], FILTER_SANITIZE_NUMBER_INT);
try {
$this->dbm->remove_options($store_id);
} catch (\Exception $e) {
$this->procesaEvent(['error' => $e->getMessage()], $e->getCode(), $req->getUri());
return $this->helper->print_json(['error' => $e->getMessage()]);
}
return $this->helper->print_json(['message' => 'App uninstalled succesfully']);
}
/**
* Sets the APP "paused"
*
* @param Request $req
* @return Response
*/
public function suspend_app(Request $req): Response
{
$webhook_content = $req->getContent();
$hmac_header = $req->headers->get('X-Linkedstore-HMAC-SHA256');
$data_received = json_decode($webhook_content, true);
if (!$this->TNApi->verify_webhook($webhook_content, $hmac_header)){
$this->procesaEvent(['error' => 'Couldn\'t verify webhook'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'Couldn\'t verify webhook'], Response::HTTP_BAD_REQUEST);
}
if (!$data_received){
$this->procesaEvent(['error' => 'Invalid JSON received'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'Invalid JSON received']);
}
$store_id = filter_var($data_received['store_id'], FILTER_SANITIZE_NUMBER_INT);
try {
$this->dbm->pause_store($store_id);
} catch (\Exception $e) {
$this->procesaEvent(['error' => '$e->getMessage()'], $e->getCode(), $req->getUri());
return $this->helper->print_json(['error' => $e->getMessage()]);
}
return $this->helper->print_json(['message' => 'App paused succesfully']);
}
/**
* Resumes the APP, making it possible to work again
*
* @param Request $req
* @return Response
*/
public function resume_app(Request $req): Response
{
$webhook_content = $req->getContent();
$hmac_header = $req->headers->get('X-Linkedstore-HMAC-SHA256');
$data_received = json_decode($webhook_content, true);
if (!$this->TNApi->verify_webhook($webhook_content, $hmac_header)){
$this->procesaEvent(['error' => 'Couldn\'t verify webhook'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'Couldn\'t verify webhook'], Response::HTTP_BAD_REQUEST);
}
if (!$data_received) {
$this->procesaEvent(['error' => 'Invalid JSON received'], Response::HTTP_BAD_REQUEST, $req->getUri());
return $this->helper->print_json(['error' => 'Invalid JSON received']);
}
$store_id = filter_var($data_received['store_id'], FILTER_SANITIZE_NUMBER_INT);
try {
$this->dbm->resume_store($store_id);
} catch (\Exception $e) {
$this->procesaEvent(['error' => $e->getMessage()], $e->getCode(), $req->getUri());
return $this->helper->print_json(['error' => $e->getMessage()]);
}
return $this->helper->print_json(['message' => 'App resumed succesfully']);
}
private function render_auth_form($store_id, $access_token): Response
{
$app_name = $this->tn_shipping_carrier_name;
return $this->render(
'auth-form.html.twig',
[
'store_id' => $store_id,
'access_token' => $access_token,
'appname' => $app_name
]
);
}
/**
* @param array $message
* @param string $code
* @param string $url
* @return void
*/
private function procesaEvent(array $message, string $code, string $url){
$event = new StoreEvent([$message, $code]);
$event->setUrl($url);
$this->dispatcher->dispatch($event, StoreEvent::STORE_EVENT);
}
}