Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SyncStravaCommand
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 6
342
0.00% covered (danger)
0.00%
0 / 1
 getAllowedAppEnvs
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 configure
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 handle
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
72
 syncStravaForYear
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 syncStravaForUserForYear
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 syncStravaLinks
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2
3namespace Olz\Command;
4
5use Olz\Command\Common\OlzCommand;
6use Olz\Entity\Anniversary\RunRecord;
7use Olz\Entity\StravaLink;
8use Symfony\Component\Console\Attribute\AsCommand;
9use Symfony\Component\Console\Command\Command;
10use Symfony\Component\Console\Input\InputArgument;
11use Symfony\Component\Console\Input\InputInterface;
12use Symfony\Component\Console\Output\OutputInterface;
13
14#[AsCommand(name: 'olz:sync-strava')]
15class SyncStravaCommand extends OlzCommand {
16    /** @return array<string> */
17    protected function getAllowedAppEnvs(): array {
18        return ['dev', 'test', 'staging', 'prod'];
19    }
20
21    protected function configure(): void {
22        $this->addArgument('year', InputArgument::REQUIRED, 'Year (YYYY)');
23        $this->addArgument('user', InputArgument::OPTIONAL, 'User ID');
24    }
25
26    protected function handle(InputInterface $input, OutputInterface $output): int {
27        $year = $input->getArgument('year');
28        if (!preg_match('/^[0-9]{4}$/', $year) || intval($year) < 1996) {
29            $this->logAndOutput("Invalid year: {$year}. Must be in format YYYY and 1996 or later.", level: 'notice');
30            return Command::INVALID;
31        }
32        $year = intval($year);
33        $user_id = $input->getArgument('user');
34        if ($user_id === null) {
35            $this->syncStravaForYear($year);
36            return Command::SUCCESS;
37        }
38        $int_user_id = $user_id ? intval($user_id) : null;
39        if (!preg_match('/^[0-9]+$/', $user_id) || intval($user_id) < 1 || !$int_user_id) {
40            $this->logAndOutput("Invalid user: {$user_id}. Must be a positive integer.", level: 'notice');
41            return Command::INVALID;
42        }
43        $this->syncStravaForUserForYear($int_user_id, $year);
44        return Command::SUCCESS;
45    }
46
47    protected function syncStravaForYear(int $year): void {
48        $this->logAndOutput("Syncing Strava for {$year}...");
49
50        $strava_link_repo = $this->entityManager()->getRepository(StravaLink::class);
51        $strava_links = $strava_link_repo->findAll();
52
53        $this->syncStravaLinks($strava_links);
54    }
55
56    protected function syncStravaForUserForYear(?int $user_id, int $year): void {
57        $this->logAndOutput("Syncing Strava for user {$user_id} for {$year}...");
58
59        $strava_link_repo = $this->entityManager()->getRepository(StravaLink::class);
60        $strava_links = $strava_link_repo->findBy(['user' => $user_id]);
61
62        $this->syncStravaLinks($strava_links);
63    }
64
65    /** @param array<StravaLink> $strava_links */
66    protected function syncStravaLinks(array $strava_links): void {
67        $is_sport_type_valid = [
68            'Run' => true,
69            'TrailRun' => true,
70            'Hike' => true,
71            'Walk' => true,
72        ];
73        $now = new \DateTime($this->dateUtils()->getIsoNow());
74        $runs_repo = $this->entityManager()->getRepository(RunRecord::class);
75        foreach ($strava_links as $strava_link) {
76            $this->logAndOutput("Syncing {$strava_link}...");
77            $user = $strava_link->getUser();
78            $access_token = $this->stravaUtils()->getAccessToken($strava_link);
79            if (!$access_token) {
80                $this->logAndOutput("{$strava_link} has no access token...", level: 'debug');
81                continue;
82            }
83            // $activities = $this->stravaUtils()->callStravaApi('GET', '/athlete/activities', [], $access_token);
84            $activities = $this->stravaUtils()->callStravaApi('GET', '/clubs/158910/activities', [], $access_token);
85            foreach ($activities as $activity) {
86                $firstname = $activity['athlete']['firstname'] ?? '';
87                $lastname = $activity['athlete']['lastname'] ?? '';
88                $distance = $activity['distance'];
89                $moving_time = $activity['moving_time'];
90                $elapsed_time = $activity['elapsed_time'];
91                $total_elevation_gain = $activity['total_elevation_gain'];
92                $sport_type = $activity['sport_type'];
93                $is_counting = $is_sport_type_valid[$sport_type] ?? false;
94                $id = md5("{$firstname}-{$lastname}-{$distance}-{$total_elevation_gain}-{$moving_time}-{$elapsed_time}");
95                $source = "strava-{$id}";
96                $existing = $runs_repo->findOneBy(['source' => $source]);
97                if ($existing !== null) {
98                    continue;
99                }
100                $this->logAndOutput("New activity: {$source} by {$firstname} {$lastname}");
101                $run = new RunRecord();
102                $this->entityUtils()->createOlzEntity($run, ['onOff' => true]);
103                $run->setUser(null);
104                $run->setRunnerName("{$firstname} {$lastname}");
105                $run->setRunAt($now);
106                $run->setIsCounting($is_counting);
107                $run->setDistanceMeters(intval($distance));
108                $run->setElevationMeters(intval($total_elevation_gain));
109                $run->setSource($source);
110                $run->setInfo(json_encode($activity) ?: null);
111                $this->entityManager()->persist($run);
112                $this->entityManager()->flush();
113            }
114        }
115    }
116}