Fix 500 error on admin access: make navigation layout resilient and auto-run pending migrations on admin entry

This commit is contained in:
2026-11-02 10:38:22 +01:00
parent 44c440222a
commit cf55f3c9f9
7 changed files with 76 additions and 9 deletions
+9 -5
View File
@@ -8,6 +8,7 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Illuminate\Validation\Rule;
use Illuminate\View\View;
@@ -26,11 +27,14 @@ class AccountController extends Controller
->latest()
->get();
$communications = Communication::where('user_id', $user->id)
->orWhere('email', strtolower($user->email))
->with('replies')
->latest()
->get();
$communications = collect();
if (Schema::hasTable('communications')) {
$communications = Communication::where('user_id', $user->id)
->orWhere('email', strtolower($user->email))
->with('replies')
->latest()
->get();
}
return view('account.index', compact('user', 'orders', 'communications'));
}
@@ -8,9 +8,11 @@ use App\Models\Communication;
use App\Models\CommunicationReply;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Schema;
use Illuminate\View\View;
class CommunicationController extends Controller
@@ -20,6 +22,10 @@ class CommunicationController extends Controller
*/
public function index(Request $request): View
{
if (! Schema::hasTable('communications')) {
Artisan::call('migrate', ['--force' => true]);
}
$query = Communication::with(['user', 'order', 'replies'])->latest();
// Status filter
@@ -8,6 +8,8 @@ use App\Models\Order;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
use Illuminate\View\View;
class CustomerController extends Controller
@@ -17,6 +19,10 @@ class CustomerController extends Controller
*/
public function index(Request $request): View
{
if (! Schema::hasTable('communications')) {
Artisan::call('migrate', ['--force' => true]);
}
$search = trim($request->input('q', ''));
// Query registered non-admin users
@@ -9,9 +9,11 @@ use App\Models\Order;
use App\Models\Setting;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Schema;
use Illuminate\View\View;
class ContactController extends Controller
@@ -60,6 +62,10 @@ class ContactController extends Controller
}
}
if (! Schema::hasTable('communications')) {
Artisan::call('migrate', ['--force' => true]);
}
$communication = Communication::create([
'user_id' => Auth::id(),
'order_id' => $orderId,
+13
View File
@@ -4,6 +4,9 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserIsAdmin
@@ -23,6 +26,16 @@ class EnsureUserIsAdmin
->with('error', 'Je hebt geen beheerderstoegang tot deze pagina.');
}
// Auto-migrate check: Ensure that new database tables (like communications) are migrated
// automatically when an admin enters the admin panel, avoiding 500 errors on Coolify/production.
try {
if (! Schema::hasTable('communications')) {
Artisan::call('migrate', ['--force' => true]);
}
} catch (\Throwable $e) {
Log::warning('Auto-migration in EnsureUserIsAdmin failed: '.$e->getMessage());
}
return $next($request);
}
}
+25 -4
View File
@@ -51,7 +51,14 @@
</a>
@php
$draftBadgeCount = \App\Models\Product::where('status', 'draft')->count();
$draftBadgeCount = 0;
try {
if (\Illuminate\Support\Facades\Schema::hasTable('products')) {
$draftBadgeCount = \App\Models\Product::where('status', 'draft')->count();
}
} catch (\Throwable $e) {
$draftBadgeCount = 0;
}
@endphp
<a href="{{ route('admin.makerworld.staging') }}" class="px-3 py-1.5 rounded-lg transition flex items-center space-x-1.5 {{ request()->routeIs('admin.makerworld.staging*') ? 'bg-slate-900 text-white font-semibold' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100' }}">
<i data-lucide="layers" class="w-3.5 h-3.5"></i>
@@ -74,7 +81,14 @@
</a>
@php
$unreadCommCount = \App\Models\Communication::where('status', 'new')->count();
$unreadCommCount = 0;
try {
if (\Illuminate\Support\Facades\Schema::hasTable('communications')) {
$unreadCommCount = \App\Models\Communication::where('status', 'new')->count();
}
} catch (\Throwable $e) {
$unreadCommCount = 0;
}
@endphp
<a href="{{ route('admin.communications.index') }}" class="px-3 py-1.5 rounded-lg transition flex items-center space-x-1.5 {{ request()->routeIs('admin.communications.*') ? 'bg-slate-900 text-white font-semibold' : 'text-slate-600 hover:text-slate-900 hover:bg-slate-100' }}">
<i data-lucide="message-square" class="w-3.5 h-3.5"></i>
@@ -101,7 +115,14 @@
<!-- Right Actions -->
<div class="flex items-center space-x-2.5">
@php
$isShopOffline = \App\Models\Setting::get('shop_offline', '0') === '1';
$isShopOffline = false;
try {
if (\Illuminate\Support\Facades\Schema::hasTable('settings')) {
$isShopOffline = \App\Models\Setting::get('shop_offline', '0') === '1';
}
} catch (\Throwable $e) {
$isShopOffline = false;
}
@endphp
<!-- Webshop Offline / Online Status Switcher -->
@@ -175,7 +196,7 @@
</header>
<!-- Offline Alert Banner -->
@if($isShopOffline ?? (\App\Models\Setting::get('shop_offline', '0') === '1'))
@if(!empty($isShopOffline))
<div class="bg-rose-500 text-white px-4 py-2.5 text-xs font-medium border-b border-rose-600 shadow-sm flex flex-col sm:flex-row items-center justify-between gap-3 sticky top-16 z-20">
<div class="flex items-center space-x-2">
<span class="w-2 h-2 rounded-full bg-white animate-pulse shrink-0"></span>
@@ -10,6 +10,7 @@ use App\Models\Order;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;
class CustomerCommunicationTest extends TestCase
@@ -231,4 +232,14 @@ class CustomerCommunicationTest extends TestCase
$this->actingAs($this->customer)->get(route('admin.communications.index'))->assertRedirect(route('home'));
$this->actingAs($this->customer)->get(route('admin.customers.index'))->assertRedirect(route('home'));
}
public function test_admin_layout_does_not_crash_even_if_communications_table_is_initially_missing(): void
{
Schema::dropIfExists('communication_replies');
Schema::dropIfExists('communications');
// Layout renders with HTTP 200 without 500 server error even when table was absent
$response = $this->actingAs($this->admin)->get(route('admin.content.index'));
$response->assertStatus(200);
}
}