Migrate backend to Porto architecture and fix minor bugs
- Fully transitioned the backend to the Porto architectural pattern - Improved code organization and maintainability - Fixed minor bugs and inconsistencies
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Containers\AppStructure\Models\Page;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class AccessCheck
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
// Проверяем, существует ли запись для текущего маршрута
|
||||
$registeredRoute = Page::where('path', '=', $request->route()->uri)
|
||||
->where('is_registered', '=', true)
|
||||
->first();
|
||||
|
||||
// Если запись не найдена, пропускаем запрос
|
||||
if (!$registeredRoute) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
// Если код не 200, возвращаем соответствующий код ошибки
|
||||
if ($registeredRoute->code != 200) {
|
||||
abort($registeredRoute->code);
|
||||
}
|
||||
|
||||
$request->attributes->set('settings_page', $registeredRoute->settings);
|
||||
// Если все проверки пройдены, продолжаем выполнение запроса
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\Authenticate as AbstractMiddleware;
|
||||
|
||||
class Authenticate extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* Get the path the user should be redirected to when they are not authenticated.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return string|null
|
||||
*/
|
||||
protected function redirectTo($request)
|
||||
{
|
||||
if (! $request->expectsJson()) {
|
||||
return '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\EncryptCookies as AbstractMiddleware;
|
||||
|
||||
class EncryptCookies extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* The names of the cookies that should not be encrypted.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Inertia\Inertia;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class EnsureUserIsSuperadmin
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!Auth::check() || !Auth::user()->hasRole('super_admin')) {
|
||||
return Inertia::render('Error', ['status' => 403])
|
||||
->toResponse($request)
|
||||
->setStatusCode(403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Containers\Widget\Models\CustomForm;
|
||||
use Carbon\Carbon;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class FormTimePeriodMiddleware
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
$form = CustomForm::select('settings')->find($request->route('id'));
|
||||
|
||||
if (!$form) {
|
||||
abort(Response::HTTP_NOT_FOUND, 'Form not found');
|
||||
}
|
||||
|
||||
|
||||
if (!isset($form->settings['period'])) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
$period = $form->settings['period'];
|
||||
|
||||
try {
|
||||
$start_time = Carbon::parse($period['start_time']);
|
||||
$end_time = Carbon::parse($period['end_time']);
|
||||
} catch (\Exception $e) {
|
||||
abort(Response::HTTP_BAD_REQUEST, 'Invalid time format');
|
||||
}
|
||||
|
||||
$now = Carbon::now();
|
||||
|
||||
if ($now >= $start_time && $now <= $end_time) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
abort(Response::HTTP_FORBIDDEN, 'Form is not available at this time');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Containers\AppStructure\Models\Page;
|
||||
use App\Ship\Resources\Breadcrumb\ClientBreadcrumbPage;
|
||||
use App\Ship\Resources\Breadcrumb\ClientBreadcrumbSection;
|
||||
use App\Ship\Resources\Breadcrumb\ClientBreadcrumbSubSection;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class GenerateBreadcrumbs
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$path = $request->path();
|
||||
$page = Page::where('path', '=', $path)
|
||||
->with('section.pages.section', 'section.mainSection')
|
||||
->first();
|
||||
|
||||
if ($page && isset($page->section)) {
|
||||
$breadcrumbs = [
|
||||
'mainSection' => new ClientBreadcrumbSection($page->section->mainSection),
|
||||
'subSection' => new ClientBreadcrumbSubSection($page->section),
|
||||
'page' => new ClientBreadcrumbPage($page),
|
||||
];
|
||||
} else {
|
||||
$breadcrumbs = null;
|
||||
}
|
||||
|
||||
$request->merge(['breadcrumbs' => $breadcrumbs]);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Containers\AppStructure\Models\MainSection;
|
||||
use App\Containers\AppStructure\UI\API\Transformers\NavigationResource;
|
||||
use App\Services\App\Breadcrumb\BreadcrumbService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Inertia\Middleware;
|
||||
use Tightenco\Ziggy\Ziggy;
|
||||
|
||||
class HandleInertiaRequests extends Middleware
|
||||
{
|
||||
protected $rootView = 'app';
|
||||
|
||||
public function version(Request $request): ?string
|
||||
{
|
||||
return parent::version($request);
|
||||
}
|
||||
|
||||
public function share(Request $request): array
|
||||
{
|
||||
// Навигация (кешированная)
|
||||
$navigation = Cache::remember('navigation', now()->addHours(1), function () {
|
||||
return NavigationResource::collection(
|
||||
MainSection::with('subSections.pages.section')
|
||||
->orderBy('sort', 'asc')
|
||||
->get()
|
||||
);
|
||||
});
|
||||
|
||||
// Хлебные крошки (автоматически по текущему URL)
|
||||
$breadcrumbs = app(BreadcrumbService::class)->generateBreadcrumbs();
|
||||
|
||||
return [
|
||||
...parent::share($request),
|
||||
'auth' => [
|
||||
'user' => $request->user() ? $request->user()->only('id', 'name', 'email', 'created_at') : null,
|
||||
],
|
||||
'ziggy' => fn () => [
|
||||
...(new Ziggy)->toArray(),
|
||||
'location' => $request->url(),
|
||||
],
|
||||
'navigation' => $navigation,
|
||||
'breadcrumbs' => $breadcrumbs, // Добавляем хлебные крошки
|
||||
'urlPrev' => function () {
|
||||
if (url()->previous() !== url()->current()) {
|
||||
return url()->previous();
|
||||
}
|
||||
return 'empty';
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class InternalRequestOnly
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$userAgent = $request->header('User-Agent');
|
||||
|
||||
// Проверяем, что User-Agent содержит ключевые слова, характерные для браузеров
|
||||
if (!preg_match('/Mozilla|Chrome|Safari|Firefox|Edge/i', $userAgent)) {
|
||||
return response('Access denied. This route is available only from a web browser.', 403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class LimitPost
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
if (auth()->user()->receivedInvitation === null) {
|
||||
return $next($request);
|
||||
}
|
||||
if (auth()->user()->receivedInvitation->post_limit > 0) {
|
||||
return $next($request);
|
||||
} else {
|
||||
throw new HttpException(403, 'Лимит постов исчерпан');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\PreventRequestsDuringMaintenance as AbstractMiddleware;
|
||||
|
||||
class PreventRequestsDuringMaintenance extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be reachable while maintenance mode is enabled.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class RateLimitCheckMiddleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$ip = $request->ip();
|
||||
$key = 'rate_limit:' . $ip;
|
||||
|
||||
// Получаем текущее количество попыток
|
||||
$attempts = Cache::get($key, 0);
|
||||
|
||||
if ($attempts >= 5) {
|
||||
return response()->json(['message' => 'Слишком много запросов, пожалуйста, попробуйте позже.'], 429);
|
||||
}
|
||||
|
||||
// Увеличиваем количество попыток
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class RateLimitCounterMiddleware
|
||||
{
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
$ip = $request->ip();
|
||||
$key = 'rate_limit:' . $ip;
|
||||
$maxAttempts = 5; // Максимальное количество попыток
|
||||
$decayMinutes = 1; // Время блокировки в минутах
|
||||
|
||||
// Получаем текущее количество попыток
|
||||
$attempts = Cache::get($key, 0);
|
||||
|
||||
if ($attempts >= $maxAttempts) {
|
||||
return response()->json(['message' => 'Слишком много запросов, пожалуйста, попробуйте позже.'], 429);
|
||||
}
|
||||
|
||||
// Увеличиваем количество попыток
|
||||
Cache::put($key, $attempts + 1, $decayMinutes * 60);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Providers\RouteServiceProvider;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
|
||||
* @param string|null ...$guards
|
||||
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function handle(Request $request, Closure $next, ...$guards)
|
||||
{
|
||||
$guards = empty($guards) ? [null] : $guards;
|
||||
|
||||
foreach ($guards as $guard) {
|
||||
if (Auth::guard($guard)->check()) {
|
||||
return redirect(RouteServiceProvider::HOME);
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
|
||||
use App\Ship\Requests\Request;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request as LaravelRequest;
|
||||
|
||||
class TransformRequestMiddleware
|
||||
{
|
||||
public function handle(LaravelRequest $request, Closure $next)
|
||||
{
|
||||
// Преобразуем стандартный Request в ваш кастомный
|
||||
$customRequest = Request::createFrom($request);
|
||||
|
||||
return $next($customRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\TrimStrings as AbstractMiddleware;
|
||||
|
||||
class TrimStrings extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* The names of the attributes that should not be trimmed.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
'current_password',
|
||||
'password',
|
||||
'password_confirmation',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\TrustHosts as AbstractMiddleware;
|
||||
|
||||
class TrustHosts extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* Get the host patterns that should be trusted.
|
||||
*
|
||||
* @return array<int, string|null>
|
||||
*/
|
||||
public function hosts()
|
||||
{
|
||||
return [
|
||||
$this->allSubdomainsOfApplicationUrl(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\TrustProxies as AbstractMiddleware;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class TrustProxies extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* The trusted proxies for this application.
|
||||
*
|
||||
* @var array<int, string>|string|null
|
||||
*/
|
||||
protected $proxies;
|
||||
|
||||
/**
|
||||
* The headers that should be used to detect proxies.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $headers =
|
||||
Request::HEADER_X_FORWARDED_FOR |
|
||||
Request::HEADER_X_FORWARDED_HOST |
|
||||
Request::HEADER_X_FORWARDED_PORT |
|
||||
Request::HEADER_X_FORWARDED_PROTO |
|
||||
Request::HEADER_X_FORWARDED_AWS_ELB;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\ValidateSignature as AbstractMiddleware;
|
||||
|
||||
class ValidateSignature extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* The names of the query string parameters that should be ignored.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
// 'fbclid',
|
||||
// 'utm_campaign',
|
||||
// 'utm_content',
|
||||
// 'utm_medium',
|
||||
// 'utm_source',
|
||||
// 'utm_term',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Ship\Middleware;
|
||||
|
||||
use App\Ship\Abstracts\Middleware\VerifyCsrfToken as AbstractMiddleware;
|
||||
|
||||
class VerifyCsrfToken extends AbstractMiddleware
|
||||
{
|
||||
/**
|
||||
* The URIs that should be excluded from CSRF verification.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user