Persistent storage volume + remove debug route + validate logo file exists
- Coolify persistent volume mounted at /app/storage/app (covers public uploads,
private files, backups). Configured via API:
POST /api/v1/applications/{uuid}/storages with type=persistent
- getLogoUrl() / getFaviconUrl() now validate file_exists($m->getPath()) before
returning URL — guards against stale DB rows from pre-volume era
- Removed /debug-storage diagnostic route (used to find the symlink+volume bug)
This commit is contained in:
@@ -98,12 +98,18 @@ class Company extends BaseTenant implements HasMedia
|
|||||||
public function getLogoUrl(): ?string
|
public function getLogoUrl(): ?string
|
||||||
{
|
{
|
||||||
$m = $this->getFirstMedia('logo');
|
$m = $this->getFirstMedia('logo');
|
||||||
return $m ? $m->getUrl() : null;
|
if (! $m) return null;
|
||||||
|
// Validate file actually exists on disk (storage may be ephemeral
|
||||||
|
// and DB row may point to lost file from previous deploy).
|
||||||
|
if (! @file_exists($m->getPath())) return null;
|
||||||
|
return $m->getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFaviconUrl(): ?string
|
public function getFaviconUrl(): ?string
|
||||||
{
|
{
|
||||||
$m = $this->getFirstMedia('favicon');
|
$m = $this->getFirstMedia('favicon');
|
||||||
return $m ? $m->getUrl() : null;
|
if (! $m) return null;
|
||||||
|
if (! @file_exists($m->getPath())) return null;
|
||||||
|
return $m->getUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,62 +46,6 @@ Route::post('/payments/paypal/webhook', [\App\Http\Controllers\PaymentController
|
|||||||
Route::post('/payments/paynet/webhook', [\App\Http\Controllers\PaymentController::class, 'paynetWebhook'])
|
Route::post('/payments/paynet/webhook', [\App\Http\Controllers\PaymentController::class, 'paynetWebhook'])
|
||||||
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
|
||||||
|
|
||||||
// DEBUG — verifică starea storage symlink + media library.
|
|
||||||
// TODO: remove after debug.
|
|
||||||
Route::get('/debug-storage', function () {
|
|
||||||
$publicStoragePath = public_path('storage');
|
|
||||||
$storageAppPublic = storage_path('app/public');
|
|
||||||
|
|
||||||
// Try to write a test file
|
|
||||||
if (! is_dir($storageAppPublic)) @mkdir($storageAppPublic, 0775, true);
|
|
||||||
@file_put_contents($storageAppPublic . '/test.txt', 'OK ' . now()->toIso8601String());
|
|
||||||
|
|
||||||
$latestMedia = \DB::table('media')->latest('id')->first();
|
|
||||||
|
|
||||||
// List contents of /app/storage/app/public
|
|
||||||
$contents = [];
|
|
||||||
if (is_dir($storageAppPublic)) {
|
|
||||||
foreach (scandir($storageAppPublic) as $item) {
|
|
||||||
if (in_array($item, ['.', '..'])) continue;
|
|
||||||
$full = $storageAppPublic . '/' . $item;
|
|
||||||
if (is_dir($full)) {
|
|
||||||
$sub = array_values(array_diff(scandir($full), ['.', '..']));
|
|
||||||
$contents[$item . '/'] = $sub;
|
|
||||||
} else {
|
|
||||||
$contents[] = $item . ' (' . filesize($full) . 'b)';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'public_storage' => [
|
|
||||||
'path' => $publicStoragePath,
|
|
||||||
'is_link' => is_link($publicStoragePath),
|
|
||||||
'exists' => file_exists($publicStoragePath),
|
|
||||||
'target' => is_link($publicStoragePath) ? readlink($publicStoragePath) : null,
|
|
||||||
'is_dir' => is_dir($publicStoragePath),
|
|
||||||
],
|
|
||||||
'storage_app_public' => [
|
|
||||||
'path' => $storageAppPublic,
|
|
||||||
'exists' => is_dir($storageAppPublic),
|
|
||||||
'test_file_written' => file_exists($storageAppPublic . '/test.txt'),
|
|
||||||
'test_file_url' => url('/storage/test.txt'),
|
|
||||||
],
|
|
||||||
'latest_media' => $latestMedia ? [
|
|
||||||
'id' => $latestMedia->id,
|
|
||||||
'model' => $latestMedia->model_type . '#' . $latestMedia->model_id,
|
|
||||||
'collection' => $latestMedia->collection_name,
|
|
||||||
'name' => $latestMedia->file_name,
|
|
||||||
'disk' => $latestMedia->disk,
|
|
||||||
'expected_path' => $storageAppPublic . '/' . $latestMedia->id . '/' . $latestMedia->file_name,
|
|
||||||
'file_exists' => file_exists($storageAppPublic . '/' . $latestMedia->id . '/' . $latestMedia->file_name),
|
|
||||||
] : null,
|
|
||||||
'media_disk_config' => config('media-library.disk_name'),
|
|
||||||
'app_url' => config('app.url'),
|
|
||||||
'storage_listing' => $contents,
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stub `login` route — needed because Laravel's auth middleware tries to
|
// Stub `login` route — needed because Laravel's auth middleware tries to
|
||||||
// route('login') when redirecting unauthenticated requests. We don't have a
|
// route('login') when redirecting unauthenticated requests. We don't have a
|
||||||
// global /login (panels use /admin/login and /app/login), so stub it.
|
// global /login (panels use /admin/login and /app/login), so stub it.
|
||||||
|
|||||||
Reference in New Issue
Block a user