opsdash-app/opsdash/lib/Controller/ReportController.php
blade34242 5cb0d79f4a Redesign email hero, add chart blocks, fix days_off, add checkpoint/recap test buttons
- Email hero: formatted period title, RECAP/CHECKPOINT badge, 2x2 stat grid,
  inline meta tags, greeting separated from title, no addHeading()
- Checkpoint vs Recap distinction in subject, badge, and footer
- Replace "Calendar pace" with Balance index in calendar_goals hero stats
- Email chart blocks: Calendar split (pie as horizontal bars) and
  Day-of-week pattern for calendar_goals; adds Category split for
  category_and_calendar_goals; charts data pre-aggregated in
  ReportSummaryService.buildChartData() with per-weekday DOW averages
- Fix: days_off no longer counts future dates in the period as quiet days
- Fix: detectTimeSummaryDisplayMode and detectTargetsDisplayMode now always
  return the strategy-mapped mode when strategy is set, preventing stale
  categories config from overriding a known onboarding strategy
- Fix: resolveTodayGroups filters today groups by active display mode
- Add Checkpoint and Recap test-send buttons to onboarding Preferences;
  test sends now always use offset=-1 (recap) or offset=0 (checkpoint)
2026-05-19 14:01:31 +07:00

92 lines
3.2 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\Opsdash\Controller;
use OCA\Opsdash\Service\ReportDeliveryService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
use OCP\IUserSession;
use Psr\Log\LoggerInterface;
final class ReportController extends Controller {
use CsrfEnforcerTrait;
use RequestGuardTrait;
private const MAX_OFFSET = 24;
private const MAX_CALS = 200;
public function __construct(
string $appName,
IRequest $request,
private IUserSession $userSession,
private LoggerInterface $logger,
private ReportDeliveryService $reportDeliveryService,
) {
parent::__construct($appName, $request);
}
#[NoAdminRequired]
public function testSend(): DataResponse {
$uid = (string)($this->userSession->getUser()?->getUID() ?? '');
if ($uid === '') {
return new DataResponse(['message' => 'unauthorized'], Http::STATUS_UNAUTHORIZED);
}
if ($csrf = $this->enforceCsrf()) {
return $csrf;
}
$data = $this->readJsonBodyDefault();
if ($data instanceof DataResponse) {
return $data;
}
$range = strtolower((string)($data['range'] ?? 'week')) === 'month' ? 'month' : 'week';
$offset = (int)($data['offset'] ?? -1);
$offset = max(-self::MAX_OFFSET, min(self::MAX_OFFSET, $offset));
$requestedCals = null;
if (isset($data['cals'])) {
$raw = is_array($data['cals']) ? $data['cals'] : [(string)$data['cals']];
$requestedCals = array_slice(array_values(array_filter(array_map(
static fn ($x) => substr(trim((string)$x), 0, 128),
$raw,
), static fn ($x) => $x !== '')), 0, self::MAX_CALS);
}
$groupsOverride = is_array($data['groups'] ?? null) ? $data['groups'] : null;
$targetsConfigOverride = is_array($data['targets_config'] ?? null) ? $data['targets_config'] : null;
$reportingConfigOverride = is_array($data['reporting_config'] ?? null) ? $data['reporting_config'] : null;
try {
$result = $this->reportDeliveryService->sendTestReport(
$this->appName,
$uid,
$range,
$offset,
$requestedCals,
$groupsOverride,
$targetsConfigOverride,
$reportingConfigOverride,
);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
} catch (\Throwable $e) {
$this->logger->error('opsdash test report send failed: ' . $e->getMessage(), [
'app' => $this->appName,
'exception' => $e,
]);
return new DataResponse(['message' => 'error'], Http::STATUS_INTERNAL_SERVER_ERROR);
}
return new DataResponse([
'ok' => true,
'email' => $result['email'],
'subject' => $result['subject'],
'summary' => $result['summary'],
], Http::STATUS_OK);
}
}