> */ protected const TRANSLATED = [Page::class, Project::class, Service::class, Call::class]; /** * Every check the caller may see, problems first. A check behind a * permission they lack is left out, as on the panel. */ public function index(Request $request, HealthReport $report): JsonResponse { // Who may open the panel's screen; each check guards itself further. $this->authorize('panel.access'); $findings = $report->runFor($request->user()); return response()->json([ 'data' => $findings->map(fn (Finding $finding) => [ 'key' => $finding->key, 'severity' => $finding->severity->value, 'count' => $finding->count, 'title' => $finding->title(), 'description' => $finding->description(), 'samples' => $finding->samples, 'panel_url' => $finding->url, ])->values(), 'meta' => [ 'problems' => $findings->filter(fn (Finding $f) => $f->severity->isProblem())->count(), 'checked_at' => now()->toIso8601String(), ], ]); } /** * Records with a language still to write (`missing`) or left behind by the * one it was translated from (`stale`, with since when). * * Filters: locale (only what that language lacks), type, published (only * what is on the site — open, for calls). */ public function translations(Request $request): JsonResponse { $locales = array_keys((array) config('locales.supported')); $request->validate([ 'locale' => ['sometimes', Rule::in($locales)], 'type' => ['sometimes', Rule::in(['pages', 'projects', 'services', 'calls'])], 'published' => ['sometimes', 'boolean'], ]); $wanted = $request->input('locale'); $items = collect(); foreach (self::TRANSLATED as $model) { $type = AdminContent::nameOf(new $model); if ($request->filled('type') && $request->input('type') !== $type) { continue; } if ($request->user()->cannot('viewAny', $model)) { continue; } $model::query() ->when($request->boolean('published'), fn ($q) => $model === Call::class ? $q->open() : $q->published()) ->with('revisions') ->get() ->each(function (Model $record) use ($locales, $wanted, $type, $items): void { $missing = array_values(array_filter( $locales, fn (string $locale) => blank($record->getTranslation('title', $locale, false)), )); $stale = collect(TranslationFreshness::for($record)) ->map(fn ($since) => $since->toIso8601String()) ->all(); if ($wanted !== null) { $missing = array_values(array_intersect($missing, [$wanted])); $stale = array_intersect_key($stale, [$wanted => true]); } if ($missing === [] && $stale === []) { return; } $items->push([ 'type' => $type, 'id' => $record->getKey(), 'title' => ContentTypes::title($record), 'missing' => $missing, 'stale' => (object) $stale, ]); }); } return response()->json(['data' => $items->values()]); } }