Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion routes/actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@
});

Route::middleware([RequireToken::class])->group(function () {
Route::any('preview/preview', [PreviewController::class, 'preview'])->name('preview');
Route::any('users/impersonate-with-token', [ImpersonationController::class, 'withToken']);
});
});
Expand Down
5 changes: 2 additions & 3 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use CraftCms\Cms\Http\Controllers\Auth\SetPasswordController;
use CraftCms\Cms\Http\Controllers\Auth\TwoFactorAuthenticationController;
use CraftCms\Cms\Http\Controllers\Auth\VerifyEmailController;
use CraftCms\Cms\Http\Controllers\SiteRouteController;
use CraftCms\Cms\Http\Middleware\RequireEdition;
use CraftCms\Cms\Route\Routes as CraftRoutes;
use CraftCms\Cms\Site\Sites;
Expand Down Expand Up @@ -69,6 +70,4 @@
});
}

Route::fallback(function () {
abort(404);
});
Route::fallback(SiteRouteController::class)->name('siteFallback');
65 changes: 2 additions & 63 deletions src/Http/Controllers/PreviewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,13 @@
namespace CraftCms\Cms\Http\Controllers;

use CraftCms\Cms\Auth\Concerns\EnforcesPermissions;
use CraftCms\Cms\Element\Drafts;
use CraftCms\Cms\Element\Elements;
use CraftCms\Cms\Http\Middleware\HandleTokenRequest;
use CraftCms\Cms\Http\Routing\ActionRoute;
use CraftCms\Cms\RouteToken\Data\RouteToken;
use CraftCms\Cms\RouteToken\RouteTokens;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Context;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Uri;

use function CraftCms\Cms\t;

Expand All @@ -42,7 +36,7 @@ public function createToken(Request $request, RouteTokens $tokens): JsonResponse
};

$token = $tokens->createPreviewToken([
route('craft.actions.preview', absolute: false), [
ActionRoute::uriForSegments(['preview', 'preview'], false), [
'elementType' => $tokenData->elementType,
'canonicalId' => $tokenData->getCanonicalId(),
'siteId' => $tokenData->siteId,
Expand All @@ -60,59 +54,4 @@ public function createToken(Request $request, RouteTokens $tokens): JsonResponse

return new JsonResponse(compact('token'));
}

public function preview(Request $request, Kernel $kernel, Elements $elements): mixed
{
$tokenData = new RouteToken($request->all());
$tokenData->validate(throw: true);

$query = $tokenData->elementType::find()
->siteId($tokenData->siteId)
->status(null);

$elementFn = match (true) {
! is_null($tokenData->draftId) => fn () => $query->draftId($tokenData->draftId)->one(),
! is_null($tokenData->revisionId) => fn () => $query->revisionId($tokenData->revisionId)->one(),
! is_null($tokenData->userId) => function () use ($tokenData, $query) {
Context::addHidden(Drafts::CONTEXT_PREVIEW_USER_ID, $tokenData->userId);

$element = (clone $query)
->draftOf($tokenData->canonicalId)
->provisionalDrafts()
->draftCreator($tokenData->userId)
->one();

return $element ?? $query->id($tokenData->canonicalId)->one();
},
default => fn () => null,
};

if ($element = $elementFn()) {
if (! $element->lft && $element->getIsDerivative()) {
// See if we can add structure data to it
$canonical = $element->getCanonical(true);
$element->structureId = $canonical->structureId;
$element->root = $canonical->root;
$element->lft = $canonical->lft;
$element->rgt = $canonical->rgt;
$element->level = $canonical->level;
}

$element->previewing = true;
$elements->setPlaceholderElement($element);
}

/** @var Uri $originalUri */
$originalUri = Context::pullHidden(HandleTokenRequest::ORIGINAL_URI_KEY);

$response = $kernel->handle($request->duplicateWithUri(
newUri: $originalUri->value(),
query: $originalUri->query()->all()
));

return match (true) {
$response instanceof Response => $response->setNoCacheHeaders(),
default => $response,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,87 @@

declare(strict_types=1);

namespace CraftCms\Cms\Http\Middleware;
namespace CraftCms\Cms\Http\Controllers;

use Closure;
use CraftCms\Cms\Cms;
use CraftCms\Cms\Element\Element;
use CraftCms\Cms\Element\Elements;
use CraftCms\Cms\ProjectConfig\ProjectConfig;
use CraftCms\Cms\Route\ControllerRoute;
use CraftCms\Cms\Route\DynamicRoute;
use CraftCms\Cms\Route\MatchedElement;
use CraftCms\Cms\Route\TemplateRoute;
use CraftCms\Cms\Site\Sites;
use CraftCms\Cms\Support\Arr;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;

use function CraftCms\Cms\t;

readonly class HandleMatchedElementRoute
readonly class SiteRouteController
{
public function __construct(
private Elements $elements,
private Sites $sites,
) {}

public function handle(Request $request, Closure $next): mixed
public function __invoke(Request $request): Response
{
$request->route()?->forgetParameter('fallbackPlaceholder');

if (! Cms::isInstalled() || ! $request->isSiteRequest() || $request->isActionRequest() || Cms::config()->headlessMode) {
return $next($request);
return response(status: 404);
}

$this->enforceOfflineAccess($request);

$path = $this->sites->getRequestPath($request);

return $this->matchElement($request, $path) ?? response(status: 404);
}

private function matchElement(Request $request, string $path): ?Response
{
if ($path === Element::HOMEPAGE_URI) {
return $next($request);
return null;
}

$element = $this->elements->getElementByUri($path, $this->sites->getCurrentSite()->id, true);

if (! $element) {
return $next($request);
if (! $element || ! $route = $element->getRoute()) {
return null;
}

$route = $element->getRoute();

if (! $route) {
return $next($request);
}
MatchedElement::set($element, $route);

if ($route instanceof ControllerRoute) {
MatchedElement::set($element, $route);

return $route->handle($request, $element);
}

if (is_string($route)) {
$route = [$route, []];
}

$routeParams = is_array($route[1] ?? null) ? $route[1] : [];
$params = Arr::get($route, 1, []);
$params = is_array($params) ? $params : [];

MatchedElement::set($element, $route);
if (Arr::get($route, 0) === 'templates/render') {
$variables = Arr::get($params, 'variables', []);
$template = Arr::get($params, 'template');

if (! is_string($template) || $template === '') {
return null;
}

return new TemplateRoute(
$template,
is_array($variables) ? $variables : [],
publicOnly: false,
)->handle($request);
}

return new DynamicRoute($route[0], $routeParams + ['publicOnly' => false])->handle($request);
return response(status: 404);
}

private function enforceOfflineAccess(Request $request): void
Expand Down
22 changes: 22 additions & 0 deletions src/Http/Middleware/CheckForUpdates.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use Closure;
use CraftCms\Cms\Cms;
use CraftCms\Cms\Config\GeneralConfig;
use CraftCms\Cms\Shared\Models\Info;
use CraftCms\Cms\Support\Arr;
use CraftCms\Cms\Support\Facades\Path;
use CraftCms\Cms\Support\File;
Expand All @@ -20,12 +22,15 @@
readonly class CheckForUpdates
{
public function __construct(
private GeneralConfig $generalConfig,
private Updates $updates,
private HandleActionRequest $handleActionRequest,
) {}

public function handle(Request $request, Closure $next): mixed
{
$this->ensureSchemaVersionIsCompatible($request);

if (! Cms::isInstalled()) {
return $next($request);
}
Expand All @@ -49,6 +54,23 @@ public function handle(Request $request, Closure $next): mixed
return $next($request);
}

private function ensureSchemaVersionIsCompatible(Request $request): void
{
if ($this->updates->isCraftSchemaVersionCompatible()) {
return;
}

if ($request->is($this->generalConfig->cpTrigger.'*')) {
$version = Info::fetch()->version;

throw new RuntimeException(t('Craft CMS does not support backtracking to this version. Please update to Craft CMS {version} or later.', [
'version' => $version,
]));
}

abort(503);
}

private function processUpdate(Request $request, Closure $next): mixed
{
if ($request->isCpRequest() && (! $request->isActionRequest() || str_contains($request->path(), 'users/login'))) {
Expand Down
39 changes: 0 additions & 39 deletions src/Http/Middleware/CheckSchemaVersion.php

This file was deleted.

8 changes: 6 additions & 2 deletions src/Http/Middleware/HandleTemplateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Closure;
use CraftCms\Cms\Cms;
use CraftCms\Cms\Http\Controllers\InstallController;
use CraftCms\Cms\Route\DynamicRoute;
use CraftCms\Cms\Route\TemplateRoute;
use CraftCms\Cms\Site\Sites;
use CraftCms\Cms\View\TemplateResolver;
use Illuminate\Http\Request;
Expand All @@ -32,6 +32,10 @@ public function handle(Request $request, Closure $next): mixed
return $response;
}

if ($request->isSiteRequest() && ! $request->routeIs('craft.siteFallback')) {
return $response;
}

/**
* Template routing is considered a fallback, so we should
* only try this once the original response is a 404.
Expand All @@ -56,7 +60,7 @@ public function handle(Request $request, Closure $next): mixed
return $response;
}

return new DynamicRoute('templates/render', ['template' => $path])->handle($request);
return new TemplateRoute($path)->handle($request);
}

private function isPublicTemplatePath(Request $request, string $path): bool
Expand Down
Loading
Loading