130 lines
4.1 KiB
PHP
130 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use RuntimeException;
|
|
|
|
class UploadController extends Controller
|
|
{
|
|
public function storeAvatar(Request $request): JsonResponse
|
|
{
|
|
$user = $request->user();
|
|
if (!$user) {
|
|
return response()->json(['message' => 'Unauthorized'], 401);
|
|
}
|
|
$this->ensurePublicStorageReady();
|
|
|
|
$data = $request->validate([
|
|
'file' => [
|
|
'required',
|
|
'image',
|
|
'mimes:jpg,jpeg,png,gif,webp',
|
|
'max:2048',
|
|
'dimensions:max_width=150,max_height=150',
|
|
],
|
|
]);
|
|
|
|
if ($user->avatar_path) {
|
|
Storage::disk('public')->delete($user->avatar_path);
|
|
}
|
|
|
|
$path = $data['file']->store('avatars', 'public');
|
|
$user->avatar_path = $path;
|
|
$user->save();
|
|
|
|
return response()->json([
|
|
'path' => $path,
|
|
'url' => Storage::url($path),
|
|
]);
|
|
}
|
|
|
|
public function storeLogo(Request $request): JsonResponse
|
|
{
|
|
$user = $request->user();
|
|
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
|
|
return response()->json(['message' => 'Forbidden'], 403);
|
|
}
|
|
$this->ensurePublicStorageReady();
|
|
|
|
$data = $request->validate([
|
|
'file' => ['required', 'file', 'mimes:jpg,jpeg,png,gif,webp,svg,ico', 'max:5120'],
|
|
]);
|
|
|
|
$path = $data['file']->store('logos', 'public');
|
|
|
|
return response()->json([
|
|
'path' => $path,
|
|
'url' => Storage::url($path),
|
|
]);
|
|
}
|
|
|
|
public function storeFavicon(Request $request): JsonResponse
|
|
{
|
|
$user = $request->user();
|
|
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
|
|
return response()->json(['message' => 'Forbidden'], 403);
|
|
}
|
|
$this->ensurePublicStorageReady();
|
|
|
|
$data = $request->validate([
|
|
'file' => ['required', 'file', 'mimes:png,ico', 'max:2048'],
|
|
]);
|
|
|
|
$path = $data['file']->store('favicons', 'public');
|
|
|
|
return response()->json([
|
|
'path' => $path,
|
|
'url' => Storage::url($path),
|
|
]);
|
|
}
|
|
|
|
private function ensurePublicStorageReady(): void
|
|
{
|
|
$storagePublic = storage_path('app/public');
|
|
$publicStorage = public_path('storage');
|
|
|
|
if (file_exists($storagePublic) && !is_dir($storagePublic)) {
|
|
@rename($storagePublic, $storagePublic.'.bak.'.date('Ymd_His'));
|
|
}
|
|
if (!is_dir($storagePublic) && !@mkdir($storagePublic, 0775, true) && !is_dir($storagePublic)) {
|
|
throw new RuntimeException('Failed to create storage/app/public directory.');
|
|
}
|
|
|
|
if (is_link($publicStorage)) {
|
|
$target = readlink($publicStorage);
|
|
$resolved = $target !== false ? realpath(dirname($publicStorage).DIRECTORY_SEPARATOR.$target) : false;
|
|
$expected = realpath($storagePublic);
|
|
if ($resolved === $expected) {
|
|
$this->ensureUploadSubdirs($storagePublic);
|
|
return;
|
|
}
|
|
@unlink($publicStorage);
|
|
} elseif (is_dir($publicStorage)) {
|
|
File::copyDirectory($publicStorage, $storagePublic);
|
|
File::deleteDirectory($publicStorage);
|
|
} elseif (file_exists($publicStorage)) {
|
|
@rename($publicStorage, $publicStorage.'.bak.'.date('Ymd_His'));
|
|
}
|
|
|
|
if (!@symlink($storagePublic, $publicStorage) && !is_link($publicStorage)) {
|
|
throw new RuntimeException('Failed to create public/storage symlink.');
|
|
}
|
|
|
|
$this->ensureUploadSubdirs($storagePublic);
|
|
}
|
|
|
|
private function ensureUploadSubdirs(string $storagePublic): void
|
|
{
|
|
foreach (['avatars', 'favicons', 'logos', 'rank-badges'] as $dir) {
|
|
$path = $storagePublic.DIRECTORY_SEPARATOR.$dir;
|
|
if (!is_dir($path)) {
|
|
@mkdir($path, 0775, true);
|
|
}
|
|
}
|
|
}
|
|
}
|