22-05-2026 Optimierung der User und Admin Panels
This commit is contained in:
parent
d2ba22c0cf
commit
e8c47b7553
73 changed files with 10282 additions and 1546 deletions
113
app/Services/PressRelease/PressReleaseAttachmentStorage.php
Normal file
113
app/Services/PressRelease/PressReleaseAttachmentStorage.php
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\PressRelease;
|
||||
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Storage for press release attachments (PDFs and other documents).
|
||||
*
|
||||
* Files are stored on the `public` disk under
|
||||
* press-releases/{id}/attachments/{uuid}-{slug}.{ext}
|
||||
*
|
||||
* Path-obscurity is sufficient for MVP: anonymous downloads are intentional
|
||||
* for published press releases, and embargo logic lives at the PR level.
|
||||
*/
|
||||
class PressReleaseAttachmentStorage
|
||||
{
|
||||
public const MAX_BYTES = 25 * 1024 * 1024;
|
||||
|
||||
/** @var list<string> */
|
||||
public const ALLOWED_EXTENSIONS = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'txt'];
|
||||
|
||||
/** @var list<string> */
|
||||
public const ALLOWED_MIMES = [
|
||||
'application/pdf',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'application/zip',
|
||||
'application/x-zip-compressed',
|
||||
'text/plain',
|
||||
];
|
||||
|
||||
/**
|
||||
* Store the uploaded attachment for the given press release.
|
||||
*
|
||||
* @return array{disk:string,path:string,original_name:string,mime:string,size:int}
|
||||
*/
|
||||
public function store(UploadedFile $upload, int $pressReleaseId): array
|
||||
{
|
||||
$this->assertValidUpload($upload);
|
||||
|
||||
$extension = strtolower($upload->getClientOriginalExtension() ?: $upload->extension());
|
||||
$originalName = $upload->getClientOriginalName();
|
||||
$baseSlug = Str::slug(pathinfo($originalName, PATHINFO_FILENAME)) ?: 'attachment';
|
||||
$baseSlug = Str::limit($baseSlug, 60, '');
|
||||
|
||||
$directory = sprintf('press-releases/%d/attachments', $pressReleaseId);
|
||||
$filename = Str::uuid()->toString().'-'.$baseSlug.'.'.$extension;
|
||||
$relativePath = $directory.'/'.$filename;
|
||||
|
||||
$disk = $this->disk();
|
||||
$stream = fopen($upload->getRealPath(), 'r');
|
||||
|
||||
if ($stream === false) {
|
||||
throw new RuntimeException('Could not open uploaded file stream.');
|
||||
}
|
||||
|
||||
try {
|
||||
$disk->put($relativePath, $stream, 'public');
|
||||
} finally {
|
||||
if (is_resource($stream)) {
|
||||
fclose($stream);
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'disk' => 'public',
|
||||
'path' => $relativePath,
|
||||
'original_name' => $originalName,
|
||||
'mime' => $upload->getMimeType() ?: 'application/octet-stream',
|
||||
'size' => $upload->getSize() ?: 0,
|
||||
];
|
||||
}
|
||||
|
||||
public function delete(string $disk, string $path): void
|
||||
{
|
||||
if (blank($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Storage::disk($disk)->delete($path);
|
||||
} catch (\Throwable) {
|
||||
// Swallow — deletion is best-effort; a missing file is acceptable.
|
||||
}
|
||||
}
|
||||
|
||||
private function assertValidUpload(UploadedFile $upload): void
|
||||
{
|
||||
$extension = strtolower($upload->getClientOriginalExtension() ?: $upload->extension());
|
||||
|
||||
if (! in_array($extension, self::ALLOWED_EXTENSIONS, true)) {
|
||||
throw new RuntimeException('Unsupported attachment extension: '.$extension);
|
||||
}
|
||||
|
||||
if ($upload->getSize() > self::MAX_BYTES) {
|
||||
throw new RuntimeException('Attachment exceeds maximum size.');
|
||||
}
|
||||
}
|
||||
|
||||
private function disk(): Filesystem
|
||||
{
|
||||
return Storage::disk('public');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue