<?php
namespace App\EventListener\Strava;
use App\Entity\Activity;
use App\Entity\SocialToken;
use App\Entity\User;
use App\Message\Event\CompileActivityEvent;
use App\Repository\ActivityRepository;
use App\Repository\SocialTokenRepository;
use Doctrine\ORM\EntityManagerInterface;
use NuBox\Strava\Api\DataObject\Activity as StravaActivity;
use NuBox\Strava\Api\Event\StravaApiEvents;
use NuBox\Strava\Api\Event\Webhook\ActivityDeletedEvent;
use NuBox\Strava\Api\Event\Webhook\WebhookEventInterface;
use NuBox\Strava\Api\Service\StravaApi;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\MessageBusInterface;
final class WebhookActivitySubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly EntityManagerInterface $entityManager,
private readonly ActivityRepository $activityRepository,
private readonly SocialTokenRepository $socialTokenRepository,
private readonly MessageBusInterface $messageBus,
private readonly StravaApi $stravaApi,
private readonly string $debugEmail
) {
}
public static function getSubscribedEvents(): array
{
return [
StravaApiEvents::WEBHOOK_ACTIVITY_CREATED => 'onActivityModified',
StravaApiEvents::WEBHOOK_ACTIVITY_UPDATED => 'onActivityModified',
StravaApiEvents::WEBHOOK_ACTIVITY_DELETED => 'onActivityDeleted',
];
}
public function onActivityModified(WebhookEventInterface $event): void
{
$activityEntry = $this->getActivity($event);
$activity = $this->stravaApi->getActivity($this->getSocialToken($event), $event->getWebhook()->getObjectId());
if ($activityEntry === null) {
$activityEntry = new Activity();
$activityEntry->setUser($this->getUser($event));
// initial payload setting
$socialPayload = $activityEntry->getSocialPayload();
$socialPayload['master'] = StravaApi::TYPE;
$activityEntry->setSocialPayload($socialPayload);
$this->entityManager->persist($activityEntry);
}
$socialPayload = $activityEntry->getSocialPayload();
$socialPayload = $this->setStravaPayload($socialPayload, $activity);
$activityEntry->setSocialPayload($socialPayload);
mail(
$this->debugEmail,
'[Wearable-Cloud] Activity Sync',
'A activity for user [' . $this->getUser($event)->getUserIdentifier() . '] was synced with payload:' . PHP_EOL .
var_export($activityEntry->getSocialPayload()[StravaApi::TYPE], true)
);
$this->entityManager->flush();
$this->messageBus->dispatch(new CompileActivityEvent($activityEntry));
}
public function onActivityDeleted(ActivityDeletedEvent $event): void
{
$activity = $this->getActivity($event);
mail(
$this->debugEmail,
'[Wearable-Cloud] Delete Activity',
'A activity for user [' . $this->getUser($event)->getUserIdentifier() . '] was deleted:' . PHP_EOL .
var_export($activity, true)
);
$this->entityManager->remove($activity);
$this->entityManager->flush();
}
private function getActivity(WebhookEventInterface $event): ?Activity
{
$activities = $this->activityRepository->findBy([
'user' => $this->getUser($event),
]);
if (count($activities) > 0) {
foreach ($activities as $activity) {
$payload = $activity->getSocialPayload();
$stravaActivity = $this->getStravaPayload($payload);
if ($stravaActivity instanceof StravaActivity) {
if ($stravaActivity->getId() === $event->getWebhook()->getObjectId()) {
return $activity;
}
}
}
}
return null;
}
private function setStravaPayload(array $payload, StravaActivity $activity): array
{
$payload[StravaApi::TYPE] = serialize($activity);
return $payload;
}
private function getStravaPayload(array $payload): ?StravaActivity
{
if (array_key_exists(StravaApi::TYPE, $payload)) {
return unserialize($payload[StravaApi::TYPE]);
}
return null;
}
private function getUser(WebhookEventInterface $event): User
{
return $this->getSocialToken($event)->getUser();
}
private function getSocialToken(WebhookEventInterface $event): SocialToken
{
$socialUserId = $event->getWebhook()->getOwnerId();
$socialToken = $this->socialTokenRepository->findOneBy([
'type' => StravaApi::TYPE,
'socialUserId' => $socialUserId,
]);
assert($socialToken instanceof SocialToken);
return $socialToken;
}
}