RprtCli/app/src/Utils/TimeTrackingServices/YoutrackService.php

250 lines
7.8 KiB
PHP

<?php
declare(strict_types=1);
// src/Utils/TimeTrackingServices/YoutrackService.php
namespace RprtCli\Utils\TimeTrackingServices;
use Exception;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ClientException;
use RprtCli\Utils\Configuration\ConfigurationInterface;
use Throwable;
use function array_combine;
use function array_filter;
use function array_map;
use function file_put_contents;
use function floor;
use function json_decode;
use function microtime;
use function readline;
use function sleep;
use function sys_get_temp_dir;
use function tempnam;
use function trim;
use function var_dump;
class YoutrackService implements YoutrackInterface
{
protected string $ytToken;
protected string $ytBaseUrl;
protected ConfigurationInterface $config;
protected ClientInterface $httpClient;
protected string $report_id;
protected ?string $reportName = null;
public function __construct(ConfigurationInterface $config, ClientInterface $http_client)
{
$this->config = $config;
$this->httpClient = $http_client;
}
public function testYoutrackapi(): ?string
{
// Get base url from config or add input.
// Get token or add input.
$path = 'youtrack/api/admin/users/me';
$yt_url = $this->getYtUrl($path);
$yt_token = $this->getYtToken();
$query = ['fields' => 'id,email,fullName'];
$headers = [
"Authorization" => "Bearer $yt_token",
'Cache-Control' => 'no-cache',
];
$me_response = $this->httpClient->request('GET', $yt_url, [
'query' => $query,
'headers' => $headers,
]);
$test = (string) $me_response->getBody()->getContents();
$me_json = (array) json_decode($test);
if ($me_json && isset($me_json['fullName'])) {
return $me_json['fullName'];
}
return null;
}
protected function requestYoutrackPath(string $path, array $query)
{
$yt_url = $this->getYtUrl($path);
$headers = $this->getHeaders();
return $this->httpClient->request('GET', $yt_url, [
'query' => $query,
'headers' => $headers,
]);
}
protected function getHeaders()
{
$yt_token = $this->getYtToken();
return [
"Authorization" => "Bearer $yt_token",
'Cache-Control' => 'no-cache',
];
}
public function getReportId(): ?string
{
// --report option value should take precedence.
// @TODO error handling.
if (isset($this->report_id)) {
return $this->report_id;
}
$yt_report_id = $this->config->get('tracking_service.youtrack.report_id');
if (! $yt_report_id) {
$yt_report_id = readline('Enter the report id: ');
}
return $yt_report_id;
}
public function setReportId(string $report_id): void
{
$this->report_id = $report_id;
}
public function setReportName(?string $report_name = null): void
{
if (! $report_name) {
$reports = $this->listReports();
if ($report_id = $this->getReportId()) {
$report_name = $reports[$report_id] ?? null;
} else {
$report_name = null;
}
}
$this->reportName = $report_name;
}
public function getReportName(): ?string
{
return $this->reportName;
}
public function downloadReport(string $report_id): ?string
{
$path = "youtrack/api/reports/$report_id/export/csv";
$query = ['$top' => -1];
$yt_token = $this->getYtToken();
$headers = [
'Accept' => 'application/json, text/plain, */*',
// 'Accept-Encoding' => 'gzip, deflate, br',
// 'Connection' => 'keep-alive',
'Accept-Language' => 'en-US,en;q=0.5',
"Authorization" => "Bearer $yt_token",
];
try {
$csv_response = $this->httpClient->request('GET', $this->getYtUrl($path), [
'headers' => $headers,
'query' => $query,
]);
// Write csv response test into temporary file.
$csv_file = tempnam(sys_get_temp_dir(), "rprt-csv-{$report_id}");
file_put_contents($csv_file, $csv_response->getBody());
return $csv_file;
} catch (ClientException $e) {
$status = $e->getResponse()->getStatusCode();
if ($status === 409) {
sleep(3);
// @TODO Find a way to break of of loop if necessary!
var_dump("409 response status during download of report {$report_id}. Sleep 3 and try again.");
return $this->downloadReport($report_id);
}
} catch (Throwable $t) {
$status = $t->getMessage();
var_dump($status);
}
throw new Exception("Unable to download report {$report_id}!");
}
protected function getYtToken(): string
{
if (isset($this->ytToken)) {
return $this->ytToken;
}
$yt_token = $this->config->get('tracking_service.youtrack.auth_token', false);
if (! $yt_token) {
$yt_token = readline('Enter your youtrack authentication token: ');
}
return $yt_token;
}
public function setYtToken(string $token): void
{
$this->ytToken = $token;
}
protected function getYtUrl(string $path = ''): ?string
{
if (isset($this->ytBaseUrl)) {
$yt_base_url = $this->ytBaseUrl;
} else {
$yt_base_url = $this->config->get('tracking_service.youtrack.base_url', false);
}
if (empty($yt_base_url)) {
$yt_base_url = readline('Enter base url for of the youtrack service: ');
}
if (! empty($path)) {
$yt_base_url .= '/' . trim($path, '/');
}
return $yt_base_url;
}
public function setYtUrl(string $base_url)
{
$this->ytBaseUrl = $base_url;
}
public function listReports(): array
{
// Now filter results by own = true;
$url = '/youtrack/api/reports';
$query = [
'$top' => -1,
'fields' => 'id,name,own,owner(login,name)',
];
$response = $this->requestYoutrackPath($url, $query);
$body = (string) $response->getBody()->getContents();
$body_json = (array) json_decode($body);
$my_reports = array_filter($body_json, fn($report) => $report->own);
$reports = array_combine(
array_map(fn($r) => $r->id, $my_reports),
array_map(fn ($r) => $r->name, $my_reports)
);
return $reports;
}
public function clearReportCache(string $report_id): int
{
$path = "/youtrack/api/reports/${report_id}/status";
$query = [
'$top' => -1,
// phpcs:ignore
'fields' => 'calculationInProgress,error(id),errorMessage,isOutdated,lastCalculated,progress,wikifiedErrorMessage',
];
$post = [
'lastCalculated' => floor(microtime(true) * 1000),
'calculationInProgress' => true,
'wikifiedErrorMessage' => '',
'isOutdated' => false,
'progress' => -1,
'error' => null,
'errorMessage' => null,
'$type' => 'ReportStatus',
];
$yt_url = $this->getYtUrl($path);
$response = $this->httpClient->request('POST', $yt_url, [
'query' => $query,
'headers' => $this->getHeaders(),
'json' => $post,
]);
// $body = (string) $response->getBody()->getContents();
// var_dump($body);
return $response->getStatusCode();
}
}