130 lines
3.3 KiB
PHP
130 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Support\Help\HelpRepository;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Str;
|
|
use Laravel\Sanctum\PersonalAccessToken;
|
|
use RuntimeException;
|
|
|
|
class HelpController extends Controller
|
|
{
|
|
public function __construct(private readonly HelpRepository $repository) {}
|
|
|
|
public function index(Request $request): JsonResponse
|
|
{
|
|
[$audience, $locale] = $this->resolveContext($request);
|
|
|
|
$articles = $this->getArticles($audience, $locale)
|
|
->map(fn ($article) => Arr::only($article, config('help.list_fields')))
|
|
->values();
|
|
|
|
return response()->json([
|
|
'data' => $articles,
|
|
]);
|
|
}
|
|
|
|
public function show(Request $request, string $slug): JsonResponse
|
|
{
|
|
[$audience, $locale] = $this->resolveContext($request);
|
|
|
|
$article = $this->getArticle($audience, $locale, $slug);
|
|
|
|
abort_if(! $article, 404, 'Help article not found.');
|
|
|
|
return response()->json([
|
|
'data' => $article,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return array{string, string}
|
|
*/
|
|
private function resolveContext(Request $request): array
|
|
{
|
|
$this->attemptTokenAuthentication($request);
|
|
|
|
$audience = Str::of($request->string('audience', 'guest'))->lower()->value();
|
|
$locale = Str::of($request->string('locale', config('help.default_locale')))->lower()->value();
|
|
|
|
if ($audience === 'admin' && ! $request->user()) {
|
|
abort(401, 'Authentication required for admin help content.');
|
|
}
|
|
|
|
if (! in_array($audience, config('help.audiences', []), true)) {
|
|
abort(400, 'Invalid audience supplied.');
|
|
}
|
|
|
|
return [$audience, $locale];
|
|
}
|
|
|
|
private function attemptTokenAuthentication(Request $request): void
|
|
{
|
|
if ($request->user()) {
|
|
return;
|
|
}
|
|
|
|
$bearer = $request->bearerToken();
|
|
|
|
if (! $bearer) {
|
|
return;
|
|
}
|
|
|
|
$token = PersonalAccessToken::findToken($bearer);
|
|
|
|
if (! $token) {
|
|
return;
|
|
}
|
|
|
|
$user = $token->tokenable;
|
|
|
|
if (! $user) {
|
|
return;
|
|
}
|
|
|
|
if (method_exists($user, 'withAccessToken')) {
|
|
$user->withAccessToken($token);
|
|
}
|
|
|
|
Auth::setUser($user);
|
|
$request->setUserResolver(fn () => $user);
|
|
}
|
|
|
|
private function getArticles(string $audience, string $locale)
|
|
{
|
|
try {
|
|
return $this->repository->list($audience, $locale);
|
|
} catch (RuntimeException $e) {
|
|
$fallback = config('help.fallback_locale');
|
|
|
|
if ($locale === $fallback) {
|
|
throw $e;
|
|
}
|
|
|
|
return $this->repository->list($audience, $fallback);
|
|
}
|
|
}
|
|
|
|
private function getArticle(string $audience, string $locale, string $slug): ?array
|
|
{
|
|
try {
|
|
$article = $this->repository->find($audience, $locale, $slug);
|
|
} catch (RuntimeException $e) {
|
|
$fallback = config('help.fallback_locale');
|
|
|
|
if ($locale !== $fallback) {
|
|
return $this->repository->find($audience, $fallback, $slug);
|
|
}
|
|
|
|
throw $e;
|
|
}
|
|
|
|
return $article;
|
|
}
|
|
}
|