<?php
declare(strict_types=1);
namespace Harmonizely\EventListener;
use Doctrine\ORM\EntityManagerInterface;
use FOS\RestBundle\Context\Context;
use FOS\RestBundle\Serializer\JMSSerializerAdapter;
use FOS\RestBundle\Serializer\Serializer;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
use Harmonizely\Model\Event;
use Harmonizely\Model\EventInterface;
use Harmonizely\Model\EventType;
use Harmonizely\Model\Integration;
use Harmonizely\Model\IntegrationInterface;
use Harmonizely\Model\Invitee;
use Harmonizely\Model\UserInterface;
use Harmonizely\Types\EventTypeDurationType;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Webmozart\Assert\Assert;
use Harmonizely\Types\IntegrationType;
final class SendZapierPayloadListener
{
/**
* @var ClientInterface
*/
private $client;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var Serializer
*/
private $serializer;
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(
ClientInterface $client,
EntityManagerInterface $entityManager,
JMSSerializerAdapter $serializer,
LoggerInterface $logger
) {
$this->client = $client;
$this->entityManager = $entityManager;
$this->serializer = $serializer;
$this->logger = $logger;
}
public function sendCreatedPayload(GenericEvent $event): void
{
$this->logger->notice('Start test ZAPIER log (create)');
$event = $event->getSubject();
Assert::isInstanceOf($event, EventInterface::class);
$user = $event->getUser();
$integration = $this->findIntegration($user);
if ($integration && $integration->isEnabled()) {
$config = $integration->getConfig();
if (!isset($config['createdWebhookUrl'])) {
return;
}
$this->logger->notice('Send scheduled meeting payload to Zapier', [
'user_email' => $user->getEmail(),
'integration_config' => $integration->getConfig(),
]);
$this->send($event, $config['createdWebhookUrl']);
}
}
public function sendCancelledPayload(GenericEvent $event): void
{
$event = $event->getSubject();
Assert::isInstanceOf($event, EventInterface::class);
$user = $event->getUser();
$integration = $this->findIntegration($user);
if ($integration && $integration->isEnabled()) {
$config = $integration->getConfig();
if (!isset($config['canceledWebhookUrl'])) {
return;
}
$this->logger->notice('Send cancelled meeting payload to Zapier', [
'user_email' => $user->getEmail(),
'integration_config' => $integration->getConfig(),
]);
$this->send($event, $config['canceledWebhookUrl']);
}
}
public function sendRescheduledPayload(GenericEvent $event): void
{
$event = $event->getSubject();
Assert::isInstanceOf($event, EventInterface::class);
$user = $event->getUser();
$integration = $this->findIntegration($user);
if ($integration && $integration->isEnabled()) {
$config = $integration->getConfig();
if (!isset($config['rescheduledWebhookUrl'])) {
return;
}
$this->logger->notice('Send rescheduled meeting payload to Zapier', [
'user_email' => $user->getEmail(),
'integration_config' => $integration->getConfig(),
]);
$this->send($event, $config['rescheduledWebhookUrl']);
}
}
private function findIntegration(UserInterface $user): ?IntegrationInterface
{
$integrationRepository = $this->entityManager->getRepository(Integration::class);
return $integrationRepository->findOneBy([
'type' => IntegrationType::TYPE_ZAPIER,
'user' => $user,
]);
}
public function sendCreatedTestPayload(GenericEvent $event): void
{
/** @var IntegrationInterface $integration */
$integration = $event->getSubject();
Assert::isInstanceOf($integration, IntegrationInterface::class);
$config = $integration->getConfig();
if (!isset($config['createdWebhookUrl'])) {
return;
}
$event = $this->createTestEvent();
$this->send($event, $config['createdWebhookUrl']);
}
public function sendCancelledTestPayload(GenericEvent $event): void
{
/** @var IntegrationInterface $integration */
$integration = $event->getSubject();
Assert::isInstanceOf($integration, IntegrationInterface::class);
$config = $integration->getConfig();
if (!isset($config['canceledWebhookUrl'])) {
return;
}
$event = $this->createTestEvent();
$event->cancel();
$this->send($event, $config['canceledWebhookUrl']);
}
public function sendRescheduledTestPayload(GenericEvent $event): void
{
/** @var IntegrationInterface $integration */
$integration = $event->getSubject();
Assert::isInstanceOf($integration, IntegrationInterface::class);
$config = $integration->getConfig();
if (!isset($config['rescheduledWebhookUrl'])) {
return;
}
$event = $this->createTestEvent();
$this->send($event, $config['rescheduledWebhookUrl']);
}
private function send(EventInterface $event, string $webhookUrl): void
{
$context = new Context();
$context->setGroups(['integration']);
$context->setSerializeNull(true);
$payload = $this->serializer->serialize($event, 'json', $context);
try {
$promise = $this->client->postAsync($webhookUrl, [
'body' => $payload,
'headers' => [
'Content-Type' => 'application/json',
'User-Agent' => 'SimplyMeet.me',
],
]);
$data = json_decode($payload, true);
$inviteeData = $data['invitee'];
$eventTypeData = $data['event_type'];
unset($data['invitee'], $data['event_type']);
$this->logger->notice('Zapier data', [
'content' => $data,
'invitee' => $inviteeData,
'event_type' => $eventTypeData,
]);
$promise->then(
function (ResponseInterface $res) {
$this->logger->notice('Zapier response', [
'status_code' => $res->getStatusCode(),
'content' => $res->getBody()->getContents(),
]);
},
function (RequestException $e) {
$this->logger->critical($e->getMessage());
}
);
$promise->wait();
} catch (\Exception $e) {
$this->logger->critical($e->getMessage());
}
}
private function createTestEvent(): EventInterface
{
$event = new Event();
$eventType = new EventType();
$eventType->setDurationType(EventTypeDurationType::FIXED_TYPE);
$eventType->setName('15 min meeting');
$eventType->setLocation('Google Meet');
$eventType->setDescription('15 minutes meeting with me.');
$eventType->setDuration(15);
$eventType->setSlug('15min');
$eventType->setTimezone('Europe/Berlin');
$event->setEventType($eventType);
$event->setScheduledAt(new \DateTime('now'));
$event->setEndDate(new \DateTime('+1 hour'));
$event->setDuration(15);
$invitee = new Invitee();
$invitee->setTimezone('Europe/Berlin');
$invitee->setEmail('doe@example.com');
$invitee->setFullName('John Doe');
$invitee->setPhoneNumber(null);
$event->setInvitee($invitee);
return $event;
}
}