- 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)
92 lines
3.2 KiB
PHP
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);
|
|
}
|
|
}
|