reports/public/index.php

231 lines
7.0 KiB
PHP

<?php declare(strict_types=1);
use Nechaev\Reports\Features\Reports\ReportsApi;
require_once __DIR__ . '/../init.php';
header('Content-Type: application/json; charset=utf-8');
/**
* @return array<int, string>
*/
function parseRepeatedQueryParam(string $key): array {
$values = [];
if (isset($_GET[$key]) && is_array($_GET[$key])) {
foreach ($_GET[$key] as $item) {
if (is_string($item) && $item !== '') {
$values[] = $item;
}
}
return array_values($values);
}
$queryString = $_SERVER['QUERY_STRING'] ?? '';
if ($queryString !== '') {
foreach (explode('&', $queryString) as $part) {
if ($part === '') {
continue;
}
[$rawName, $rawValue] = array_pad(explode('=', $part, 2), 2, '');
$name = urldecode($rawName);
if ($name !== $key && $name !== $key . '[]') {
continue;
}
$value = urldecode($rawValue);
if ($value !== '') {
$values[] = $value;
}
}
}
if ($values === [] && isset($_GET[$key]) && is_string($_GET[$key]) && $_GET[$key] !== '') {
return [$_GET[$key]];
}
return array_values($values);
}
/**
* @return array<int, string>
*/
function parseStringList(mixed $value): array {
if ($value === null || $value === '') {
return [];
}
$items = is_array($value) ? $value : [$value];
return array_values(array_filter(array_map('strval', $items), static fn (string $item): bool => $item !== ''));
}
/**
* @return array<int, string>
*/
function parseStringListFromQuery(string $key): array {
return parseStringList(parseRepeatedQueryParam($key));
}
/**
* @return array<int, int>
*/
function parseIntList(mixed $value): array {
$items = parseStringList($value);
return array_values(array_filter(array_map('intval', $items), static fn (int $item): bool => $item > 0));
}
/**
* @return array<int, int>
*/
function parseIntListFromQuery(string $key): array {
return parseIntList(parseRepeatedQueryParam($key));
}
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$path = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?: '/';
if ($method === 'OPTIONS') {
http_response_code(204);
exit;
}
try {
$api = new ReportsApi();
if ($method === 'GET' && $path === '/api/teams') {
echo json_encode($api->getTeams(), JSON_UNESCAPED_UNICODE);
exit;
}
if ($method === 'GET' && $path === '/api/config') {
echo json_encode($api->getPublicConfig(), JSON_UNESCAPED_UNICODE);
exit;
}
if ($method === 'GET' && preg_match('#^/api/teams/(\d+)/sprints$#', $path, $matches)) {
echo json_encode($api->getSprintsByTeamId((int) $matches[1]), JSON_UNESCAPED_UNICODE);
exit;
}
if ($method === 'GET' && preg_match('#^/api/teams/(\d+)/tasks/filters$#', $path, $matches)) {
$result = $api->getTeamTaskFilterOptions((int) $matches[1]);
if ($result === null) {
http_response_code(404);
echo json_encode(['error' => 'Team not found'], JSON_UNESCAPED_UNICODE);
exit;
}
echo json_encode($result, JSON_UNESCAPED_UNICODE);
exit;
}
if ($method === 'GET' && preg_match('#^/api/teams/(\d+)/tasks/export$#', $path, $matches)) {
$result = $api->getAllTasksByTeamId(
(int) $matches[1],
parseStringListFromQuery('task_type'),
parseStringListFromQuery('assignee'),
parseIntListFromQuery('sprint_id')
);
if ($result === null) {
http_response_code(404);
echo json_encode(['error' => 'Team not found'], JSON_UNESCAPED_UNICODE);
exit;
}
$fileName = sprintf('ltd_%s_%s.csv', $result['team_id'], date('Y-m-d'));
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
$output = fopen('php://output', 'wb');
// BOM для корректного распознавания UTF-8 в Excel.
fwrite($output, "\xEF\xBB\xBF");
fputcsv($output, [
'Задача',
'Название',
'Спринт',
'Тип',
'Исполнитель',
'Роль',
'Оценка (сек)',
'Факт (сек)',
'Lead Time (дни)',
'Переработка (%)',
'Flow Efficiency (%)',
'Ревью',
'Тест',
'Взято в работу',
'Закрыта',
], ';', '"', '');
foreach ($result['items'] as $item) {
fputcsv($output, [
$item['task_key'],
$item['task_title'],
$item['sprint_name'],
$item['task_type'],
$item['employee_name'] ?? '',
$item['employee_role'] ?? '',
$item['estimate_seconds'],
$item['total_time_seconds'],
$item['lead_time_days'] ?? '',
$item['recast_percentage'] ?? '',
$item['efficiency_percentage'] ?? '',
$item['review_count'],
$item['test_count'],
$item['take_in_work_datetime'] ?? '',
$item['resolution_datetime'] ?? '',
], ';', '"', '');
}
fclose($output);
exit;
}
if ($method === 'GET' && preg_match('#^/api/teams/(\d+)/tasks$#', $path, $matches)) {
$page = max(1, (int) ($_GET['page'] ?? 1));
$perPage = max(1, min(100, (int) ($_GET['per_page'] ?? 50)));
$result = $api->getTasksByTeamId(
(int) $matches[1],
$page,
$perPage,
parseStringListFromQuery('task_type'),
parseStringListFromQuery('assignee'),
parseIntListFromQuery('sprint_id')
);
if ($result === null) {
http_response_code(404);
echo json_encode(['error' => 'Team not found'], JSON_UNESCAPED_UNICODE);
exit;
}
echo json_encode($result, JSON_UNESCAPED_UNICODE);
exit;
}
if ($method === 'GET' && preg_match('#^/api/sprints/(\d+)/tasks$#', $path, $matches)) {
echo json_encode($api->getTasksBySprintId((int) $matches[1]), JSON_UNESCAPED_UNICODE);
exit;
}
if ($method === 'GET' && preg_match('#^/api/sprints/(\d+)$#', $path, $matches)) {
$sprint = $api->getSprintById((int) $matches[1]);
if ($sprint === null) {
http_response_code(404);
echo json_encode(['error' => 'Sprint not found'], JSON_UNESCAPED_UNICODE);
exit;
}
echo json_encode($sprint, JSON_UNESCAPED_UNICODE);
exit;
}
http_response_code(404);
echo json_encode(['error' => 'Not found'], JSON_UNESCAPED_UNICODE);
} catch (Throwable $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
}