File "BaseExceptionHandler.php"
Full Path: /var/www/drive/foundation/src/Core/Exceptions/BaseExceptionHandler.php
File size: 6.95 KB
MIME-type: text/x-php
Charset: utf-8
<?php
namespace Common\Core\Exceptions;
use Common\Billing\Models\Product;
use ErrorException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Exceptions\Handler;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Sentry\Laravel\Integration;
use Sentry\State\Scope;
use Spatie\Ignition\Ignition;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Throwable;
use function Sentry\configureScope;
class BaseExceptionHandler extends Handler
{
public function render($request, Throwable $e)
{
$isAuthException =
$e instanceof AuthorizationException ||
($e instanceof HttpException && $e->getStatusCode() === 403);
if (
$isAuthException &&
(requestIsFromFrontend() &&
!$request->expectsJson() &&
!Auth::check())
) {
return redirect('/login');
}
if (
$e instanceof AuthorizationException &&
$e->response() instanceof AccessResponseWithPermission &&
$e->response()->permission &&
Auth::check() &&
settings('billing.enable')
) {
$permissionExistsInSubscriptionPlan = Product::with(['permissions'])
->get()
->some(function ($product) use ($e) {
// check if there's a plan that has this permission and if user is not already on this plan
return $product->permissions->contains(
'name',
$e->response()->permission,
) &&
Auth::user()->subscriptions->first()?->product_id !==
$product->id;
});
if ($permissionExistsInSubscriptionPlan) {
return Auth::user()->subscribed()
? redirect('/billing')
: redirect('/pricing');
}
}
return parent::render($request, $e);
}
public function register()
{
if (config('app.env') !== 'production') {
return;
}
$this->renderable(function (ErrorException $e) {
if (
Str::contains($e->getMessage(), [
'failed to open stream: Permission denied',
'mkdir(): Permission denied',
])
) {
return $this->filePermissionResponse($e);
}
});
configureScope(function (Scope $scope): void {
$scope->setContext('app_name', ['value' => config('app.name')]);
});
$this->reportable(function (Throwable $e) {
Integration::captureUnhandledException($e);
});
}
protected function convertExceptionToArray(Throwable $e): array
{
$previous = $e->getPrevious();
$isValidationException =
$e instanceof HttpException && $e->getStatusCode() === 422;
$isExceptionWithAction =
$previous &&
method_exists($previous, 'response') &&
$previous->response() &&
property_exists($previous->response(), 'action');
if (
config('app.debug') &&
!config('common.site.demo') &&
!$isValidationException &&
false
) {
$array = $this->ignitionReportFromThrowable($e);
} else {
$array = parent::convertExceptionToArray($e);
}
if ($isExceptionWithAction) {
$array['action'] = $e->getPrevious()->response()->action;
}
if ($array['message'] === 'Server Error') {
$array['message'] = __(
'There was an issue. Please try again later.',
);
}
if ($array['message'] === 'This action is unauthorized.') {
$array['message'] = __(
"You don't have required permissions for this action.",
);
}
return $array;
}
protected function filePermissionResponse(ErrorException $e)
{
if (request()->expectsJson()) {
return response()->json(['message' => 'test']);
} else {
preg_match('/\((.+?)\):/', $e->getMessage(), $matches);
$path = $matches[1] ?? null;
// should not return a view here, in case laravel views folder is not readable as well
return response(
"<div style='text-align:center'><h1>Could not access a file or folder</h1> <br> Location: <b>$path</b><br>" .
'<p>See the article here for possible solutions: <a target="_blank" href="https://support.vebto.com/hc/articles/21/25/207/changing-file-permissions">https://support.vebto.com/hc/articles/207/changing-file-permissions</a></p></div>',
);
}
}
protected function ignitionReportFromThrowable(Throwable $e): array
{
$report = app(Ignition::class)
->shouldDisplayException(false)
->handleException($e)
->toArray();
$trace = array_map(function ($item) {
$path = Str::of($item['class'] ?? $item['file'])
->replace([base_path(), 'vendor/laravel/framework/src/'], '')
->replace('\\', '/')
->trim('/')
->explode('/');
return [
'applicationFrame' => $item['application_frame'],
'codeSnippet' => $item['code_snippet'],
'path' => $path,
'lineNumber' => $item['line_number'],
'method' => $item['method'],
];
}, $report['stacktrace']);
$flatIndex = 0;
$totalVendorGroups = 0;
$groupedTrace = array_reduce(
$trace,
function ($carry, $item) use (&$flatIndex, &$totalVendorGroups) {
$item['flatIndex'] = $flatIndex;
if ($item['applicationFrame']) {
$carry[] = $item;
} else {
if (Arr::get(Arr::last($carry), 'vendorGroup')) {
$carry[count($carry) - 1]['items'][] = $item;
} else {
$totalVendorGroups++;
$carry[] = [
'vendorGroup' => true,
'items' => [$item],
];
}
}
$flatIndex++;
return $carry;
},
[],
);
return [
'ignitionTrace' => true,
'message' => $report['message'],
'exception' => $report['exception_class'],
'file' => $report['stacktrace'][0]['file'],
'line' => $report['stacktrace'][0]['line_number'],
'trace' => $groupedTrace,
'totalVendorGroups' => $totalVendorGroups,
'phpVersion' => $report['language_version'],
'appVersion' => config('common.site.version'),
];
}
}