Reworked maintenance system. Also had to rework a few HTTP error related things because the 404 page wasn't being run through middleware.
This commit is contained in:
parent
4a06844a53
commit
0e4cec86cc
|
|
@ -50,12 +50,15 @@ class Handler extends ExceptionHandler
|
|||
return response()->view('errors.403', [], 403);
|
||||
});
|
||||
|
||||
/*
|
||||
// Moved to route fallback
|
||||
$this->renderable(function (NotFoundHttpException $e, $request) {
|
||||
return response()->view('errors.404', [], 404);
|
||||
});
|
||||
|
||||
// Moved to middleware
|
||||
$this->renderable(function (\ErrorException $e, $request) {
|
||||
return response()->view('errors.500', ['stack' => $e->getTraceAsString()], 500);
|
||||
});
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class Kernel extends HttpKernel
|
|||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -30,6 +30,7 @@ class Kernel extends HttpKernel
|
|||
*/
|
||||
protected $middlewareGroups = [
|
||||
'web' => [
|
||||
\App\Http\Middleware\Exception\WebException::class,
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
|
|
@ -39,22 +40,12 @@ class Kernel extends HttpKernel
|
|||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
],
|
||||
|
||||
'admin' => [
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
// \Illuminate\Session\Middleware\AuthenticateSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
'throttle:api',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware\Exception;
|
||||
|
||||
use Closure;
|
||||
|
||||
class WebException
|
||||
{
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
|
||||
if ($response->exception) {
|
||||
return response()->view('errors.500', ['stack' => $response->exception->getTraceAsString()], 500);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,139 +3,33 @@
|
|||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Foundation\Http\MaintenanceModeBypassCookie;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class PreventRequestsDuringMaintenance
|
||||
{
|
||||
/**
|
||||
* The application implementation.
|
||||
*
|
||||
* @var \Illuminate\Contracts\Foundation\Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* The URIs that should be accessible while maintenance mode is enabled.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = ['maintenance', 'maintenance/bypass'];
|
||||
|
||||
/**
|
||||
* Create a new middleware instance.
|
||||
*
|
||||
* @param \Illuminate\Contracts\Foundation\Application $app
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Application $app)
|
||||
protected $app;
|
||||
public function __construct(Application $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($this->app->isDownForMaintenance()) {
|
||||
$data = json_decode(file_get_contents($this->app->storagePath().'/framework/down'), true);
|
||||
|
||||
if ($this->hasValidBypassCookie($request, $data) ||
|
||||
$this->inExceptArray($request)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
return response('{"errors":[{"code":503,"message":"ServiceUnavailable"}]}', 503)
|
||||
->header('Cache-Control', 'private')
|
||||
->header('Content-Type', 'application/json; charset=utf-8');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the incoming request has a maintenance mode bypass cookie.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasValidBypassCookie($request, array $data)
|
||||
{
|
||||
return isset($data['secret']) &&
|
||||
$request->cookie('gt_constraint') &&
|
||||
MaintenanceModeBypassCookie::isValid(
|
||||
$request->cookie('gt_constraint'),
|
||||
$data['secret']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the request has a URI that should be accessible in maintenance mode.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function inExceptArray($request)
|
||||
{
|
||||
foreach ($this->except as $except) {
|
||||
if ($except !== '/') {
|
||||
$except = trim($except, '/');
|
||||
}
|
||||
|
||||
if ($request->fullUrlIs($except) || $request->is($except)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect the user back to the root of the application with a maintenance mode bypass cookie.
|
||||
*
|
||||
* @param string $secret
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
protected function bypassResponse(string $secret)
|
||||
{
|
||||
return redirect('/')->withCookie(
|
||||
MaintenanceModeBypassCookie::create($secret)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the headers that should be sent with the response.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
protected function getHeaders($data)
|
||||
{
|
||||
$headers = isset($data['retry']) ? ['Retry-After' => $data['retry']] : [];
|
||||
|
||||
if (isset($data['refresh'])) {
|
||||
$headers['Refresh'] = $data['refresh'];
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URIs that should be accessible even when maintenance mode is enabled.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getExcludedPaths()
|
||||
{
|
||||
return $this->except;
|
||||
}
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if($this->app->isDownForMaintenance()) {
|
||||
if(in_array('web', $request->route()->middleware()))
|
||||
{
|
||||
if($request->route()->uri() != 'maintenance')
|
||||
return redirect('/maintenance?ReturnUrl=' . urlencode(url()->full()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return response(['errors' => [['code' => 503, 'message' => 'ServiceUnavailable']]], 503)
|
||||
->header('Cache-Control', 'private')
|
||||
->header('Content-Type', 'application/json; charset=utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class MaintenanceServiceProvider extends ServiceProvider
|
||||
{
|
||||
protected $app;
|
||||
public function __construct(Application $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
Blade::directive('live', function() {
|
||||
return '<?php if(!app()->isDownForMaintenance()): ?>';
|
||||
});
|
||||
|
||||
Blade::directive('endlive', function() {
|
||||
return '<?php endif; ?>';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->configureRateLimiting();
|
||||
//$this->configureRateLimiting();
|
||||
|
||||
$this->routes(function () {
|
||||
Route::domain('apis.' . env('APP_URL'))
|
||||
|
|
@ -66,7 +66,7 @@ class RouteServiceProvider extends ServiceProvider
|
|||
->group(base_path('routes/versioncompatibility.php'));
|
||||
|
||||
Route::domain('impulse.' . env('APP_URL'))
|
||||
->middleware('admin')
|
||||
->middleware('web')
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/admin.php'));
|
||||
|
||||
|
|
@ -82,15 +82,15 @@ class RouteServiceProvider extends ServiceProvider
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the rate limiters for the application.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configureRateLimiting()
|
||||
{
|
||||
RateLimiter::for('api', function (Request $request) {
|
||||
return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
|
||||
});
|
||||
}
|
||||
// /**
|
||||
// * Configure the rate limiters for the application.
|
||||
// *
|
||||
// * @return void
|
||||
// */
|
||||
// protected function configureRateLimiting()
|
||||
// {
|
||||
// RateLimiter::for('api', function (Request $request) {
|
||||
// return Limit::perMinute(60)->by(optional($request->user())->id ?: $request->ip());
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ return [
|
|||
/*
|
||||
* Laravel Framework Service Providers...
|
||||
*/
|
||||
Illuminate\Auth\AuthServiceProvider::class,
|
||||
App\Providers\MaintenanceServiceProvider::class,
|
||||
Illuminate\Broadcasting\BroadcastServiceProvider::class,
|
||||
Illuminate\Bus\BusServiceProvider::class,
|
||||
Illuminate\Cache\CacheServiceProvider::class,
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@
|
|||
|
||||
@section('content')
|
||||
<div class="container graphictoria-center-vh">
|
||||
@env(['staging', 'local'])
|
||||
<br />
|
||||
@endenv
|
||||
<x-card title="INTERNAL SERVER ERROR">
|
||||
<x-slot name="body">
|
||||
Oops, we ran into an issue while trying to process your request, please try again later in a few minutes. If the issue persists after a few minutes, please contact us at <a href="mailto:support@gtoria.net" class="fw-bold text-decoration-none">support@gtoria.net</a>.
|
||||
@env(['production', 'staging'])
|
||||
@env(['staging', 'local'])
|
||||
@if(isset($stack))
|
||||
<div class="border border-primary bg-dark p-3 m-4">
|
||||
<code>
|
||||
|
|
@ -24,5 +27,8 @@
|
|||
</div>
|
||||
</x-slot>
|
||||
</x-card>
|
||||
@env(['staging', 'local'])
|
||||
<br />
|
||||
@endenv
|
||||
</div>
|
||||
@endsection
|
||||
|
|
|
|||
|
|
@ -31,18 +31,20 @@
|
|||
<div class="footer mt-auto pt-3 text-center shadow-lg">
|
||||
<div class="container">
|
||||
<h4 class="fw-bold mb-0">Graphictoria</h4>
|
||||
<p class="text-muted fw-bold mb-0 mt-1">
|
||||
@foreach($routes as $index => $route)
|
||||
@php
|
||||
// HACK
|
||||
$route = (object)$route;
|
||||
@endphp
|
||||
<a class="text-decoration-none fw-normal" href="{{ url($route->location) }}"{{ $route->label == 'Blog' ? ' target="_blank"' : '' }}>{{ $route->label }}</a>
|
||||
@if($index != array_key_last($routes))
|
||||
{{ ' | ' }}
|
||||
@endif
|
||||
@endforeach
|
||||
</p>
|
||||
@live
|
||||
<p class="text-muted fw-bold mb-0 mt-1">
|
||||
@foreach($routes as $index => $route)
|
||||
@php
|
||||
// HACK
|
||||
$route = (object)$route;
|
||||
@endphp
|
||||
<a class="text-decoration-none fw-normal" href="{{ url($route->location) }}"{{ $route->label == 'Blog' ? ' target="_blank"' : '' }}>{{ $route->label }}</a>
|
||||
@if($index != array_key_last($routes))
|
||||
{{ ' | ' }}
|
||||
@endif
|
||||
@endforeach
|
||||
</p>
|
||||
@endlive
|
||||
<hr class="mx-auto my-2 w-25"/>
|
||||
<p class="text-muted fw-light m-0">Copyright © {{ \Carbon\Carbon::now()->format('Y') }} Graphictoria. All rights reserved.</p>
|
||||
<p class="text-muted fw-light m-0">Graphictoria is not affiliated with, endorsed by, or sponsored by Roblox Corporation. The usage of this website signifies your acceptance of the <a class="text-decoration-none fw-normal" href="{{ url('/legal/terms-of-use') }}">Terms of Use</a> and our <a class="text-decoration-none fw-normal" href="{{ url('/legal/privacy-policy') }}">Privacy Policy</a>.</p>
|
||||
|
|
|
|||
|
|
@ -18,55 +18,69 @@
|
|||
|
||||
<div class="navbar graphictoria-navbar fixed-top navbar-expand-md shadow-sm">
|
||||
<div class="container-md">
|
||||
<a class="navbar-brand" href="/">
|
||||
<img src="{{ asset('/images/logo.png') }}" alt="Graphictoria" width="43" height="43" draggable="false"/>
|
||||
</a>
|
||||
@live
|
||||
<a class="navbar-brand" href="/">
|
||||
<img src="{{ asset('/images/logo.png') }}" alt="Graphictoria" width="43" height="43" draggable="false"/>
|
||||
</a>
|
||||
@else
|
||||
<i class="navbar-brand">
|
||||
<img src="{{ asset('/images/logo.png') }}" alt="Graphictoria" width="43" height="43" draggable="false"/>
|
||||
</i>
|
||||
@endlive
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#graphictoria-nav" aria-controls="graphictoria-nav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="graphictoria-nav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
@foreach($routes as $route)
|
||||
@php
|
||||
// HACK
|
||||
$route = (object)$route;
|
||||
@endphp
|
||||
<li class="nav-item">
|
||||
<a @class(['nav-link', 'active'=>str_starts_with(Request::path(), $route->location)]) href="{{ url('/' . $route->location) }}">{{ $route->label }}</a>
|
||||
</li>
|
||||
@endforeach
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="graphictoria-nav-dropdown" role="button" data-bs-toggle="dropdown" area-expanded="false">More</a>
|
||||
<ul class="dropdown-menu graphictoria-nav-dropdown" area-labelledby="graphictoria-nav-dropdown">
|
||||
<li><a @class(['dropdown-item', 'active'=>str_starts_with(Request::path(), 'users')]) href="{{ url('/users') }}">Users</a></li>
|
||||
<li><a class="dropdown-item" href="https://discord.gg/q666a2sF6d" target="_blank" rel="noreferrer">Discord</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@if($authenticated)
|
||||
<div class="flex">
|
||||
<p class="my-auto me-2 text-muted" style="color:#e59800!important;font-weight:bold">
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tokens are Graphictoria's currency.">
|
||||
<img src="{{ asset('images/symbols/token.svg') }}" height="20" width="20" class="img-fluid me-1" style="margin-top:-1px" />
|
||||
123
|
||||
</span>
|
||||
</p>
|
||||
<div class="dropdown">
|
||||
<a class="nav-link dropdown-toggle graphictoria-user-dropdown" href="#" id="graphictoria-user-dropdown" role="button" data-bs-toggle="dropdown" area-expanded="false">
|
||||
<span class="d-flex align-items-center">
|
||||
<img src="{{ asset('images/testing/headshot.png') }}" class="img-fluid border me-1 graphictora-user-circle" width="37" height="37">
|
||||
<p>Username</p>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu graphictoria-user-dropdown" area-labelledby="graphictoria-user-dropdown">
|
||||
<li><a class="dropdown-item" href="{{ url('/my/settings') }}">Settings</a></li>
|
||||
<li><a class="dropdown-item" href="{{ url('/my/logout') }}">Logout</a></li>
|
||||
@live
|
||||
@foreach($routes as $route)
|
||||
@php
|
||||
// HACK
|
||||
$route = (object)$route;
|
||||
@endphp
|
||||
<li class="nav-item">
|
||||
<a @class(['nav-link', 'active'=>str_starts_with(Request::path(), $route->location)]) href="{{ url('/' . $route->location) }}">{{ $route->label }}</a>
|
||||
</li>
|
||||
@endforeach
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="graphictoria-nav-dropdown" role="button" data-bs-toggle="dropdown" area-expanded="false">More</a>
|
||||
<ul class="dropdown-menu graphictoria-nav-dropdown" area-labelledby="graphictoria-nav-dropdown">
|
||||
<li><a @class(['dropdown-item', 'active'=>str_starts_with(Request::path(), 'users')]) href="{{ url('/users') }}">Users</a></li>
|
||||
<li><a class="dropdown-item" href="https://discord.gg/q666a2sF6d" target="_blank" rel="noreferrer">Discord</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@else
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://discord.gg/q666a2sF6d" target="_blank" rel="noreferrer">Discord</a>
|
||||
</li>
|
||||
@endlive
|
||||
</ul>
|
||||
@live
|
||||
@if($authenticated)
|
||||
<div class="flex">
|
||||
<p class="my-auto me-2 text-muted" style="color:#e59800!important;font-weight:bold">
|
||||
<span data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tokens are Graphictoria's currency.">
|
||||
<img src="{{ asset('images/symbols/token.svg') }}" height="20" width="20" class="img-fluid me-1" style="margin-top:-1px" />
|
||||
123
|
||||
</span>
|
||||
</p>
|
||||
<div class="dropdown">
|
||||
<a class="nav-link dropdown-toggle graphictoria-user-dropdown" href="#" id="graphictoria-user-dropdown" role="button" data-bs-toggle="dropdown" area-expanded="false">
|
||||
<span class="d-flex align-items-center">
|
||||
<img src="{{ asset('images/testing/headshot.png') }}" class="img-fluid border me-1 graphictora-user-circle" width="37" height="37">
|
||||
<p>Username</p>
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu graphictoria-user-dropdown" area-labelledby="graphictoria-user-dropdown">
|
||||
<li><a class="dropdown-item" href="{{ url('/my/settings') }}">Settings</a></li>
|
||||
<li><a class="dropdown-item" href="{{ url('/my/logout') }}">Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<a class="btn btn-success" href="/login">Login / Sign up</a>
|
||||
@endif
|
||||
@else
|
||||
<a class="btn btn-success" href="/login">Login / Sign up</a>
|
||||
@endif
|
||||
@endlive
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -22,3 +22,8 @@ Route::view('/javascript', 'javascript');
|
|||
|
||||
// client
|
||||
Route::get('/asset', 'ContentController@fetchAsset');
|
||||
|
||||
// fallback
|
||||
Route::fallback(function(){
|
||||
return response()->view('errors.404', [], 404);
|
||||
});
|
||||
Loading…
Reference in New Issue